0

I have a pipeline of asynchronous operations that takes a long time to complete, and I would like to let the Uni continue with a placeholder item if the pipeline has not produced an item before a deadline, like this:

Uni<Item> u = processingPipeline();
return u.ifNoItem().after(Duration.of(10, SECONDS)).recoverWith(placeholderItem);

But when this method is used the processing pipeline is cancelled and the chain of operations are interrupted. Is it possible to complete the Uni with a placeholder item when the deadline expires without cancelling the processing pipeline? I would like the pipeline to carry on to the end even if the deadline is missed. Vert.x is available if that helps.

Thanks

Edit:

This is what I've tried so far:

Uni<Item> u = processingPipeline();
return Uni.createFrom().emitter(emitter -> {
    vertx.executeBlocking(handler -> {
        u.subscribe().with(emitter::complete);
    }, resultHandler -> {});
    vertx.setTimer(TimeUnit.SECONDS.toMillis(10), timerId -> {
        emitter.complete(placeholderItem);
    });
});

And this works fine when the processing is completed before the deadline, but if the deadline expires and the timer is fired it crashes with javax.enterprise.context.ContextNotActiveException when the placeholder item is emitted, and also the application seems to get stuck in some sort of deadlock.

Edit 2

Turns out most of my problems were actually caused by improper use of Hibernate. After some refactoring of how the Hibernate transactions are managed all random deadlocks and other issues went away.

This seems to be the most elegant solution to the original question, i.e. how to respond with a dummy item without interrupting the processing unless it completed before a deadline:

Uni<Item> u = processingPipeline();
return Uni.createFrom().emitter(emitter -> {
    u.subscribe().with(emitter::complete);
    vertx.setTimer(TimeUnit.SECONDS.toMillis(10), timerId -> {
        emitter.complete(placeholderItem);
    });
});
sirf
  • 3
  • 2

1 Answers1

2

The cancellation of the pipeline is to be expected, since ifNoItem().after(duration) triggers a TimeoutException. So this exception is propagated as a failure, and the upstream at this particular point is cancelled, which is in line with reactive streams semantics.

recoverWith is a failure recovery operator, and whatever is down the line after this operator is subscribed to it.

You may want to have a look at recoverWithUni, where you would provide a Uni as a recovery, and that Uni would capture the rest of the pipeline that may be re-subscribed to after this particular point of timeout failure.

Hope that helps.

jponge
  • 510
  • 2
  • 4