Skip to content

Delaying a Uni should not move the context to an executor thread in Quarkus #50918

@wjglerum

Description

@wjglerum

When writing some reactive code you can delay a Uni by a certain duration:

Uni.createFrom().item("item").onItem().delayIt().by(Duration.ofSeconds(1))

See https://smallrye.io/smallrye-mutiny/latest/guides/delaying-events/

If you then start combining this with Hibernate Reactive you will get big stacktraces telling you not to do this as it's not allowed.

HR000069: Detected use of the reactive Session from a different Thread than the one which was used to open the reactive Session - this suggests an invalid integration; original thread [222]: 'vert.x-eventloop-thread-2' current Thread [214]: 'executor-thread-1'

And the error is correct, as the delay gets scheduled on a worker thread and not on the event loop, see https://github.com/smallrye/smallrye-mutiny/blob/main/implementation/src/main/java/io/smallrye/mutiny/groups/UniOnItemDelay.java#L34

I created a small reproducer based on a quickstart to showcase this, see quarkusio/quarkus-quickstarts@main...wjglerum:panache-transaction-delay

Here you can see that after the delay it now runs on a worker thread:

2025-11-05 16:12:32,724 INFO  [org.acm.hib.orm.pan.FruitResource] (vert.x-eventloop-thread-2) Fruit<1>
2025-11-05 16:12:33,730 INFO  [org.acm.hib.orm.pan.FruitResource] (executor-thread-1) Fruit<1>

After discussing on Zulip (see https://quarkusio.zulipchat.com/#narrow/channel/187030-users/topic/Quarkus.20Hibernate.20Reactive.20Panache.20with.20a.20delay.20in.20a.20Uni/with/554127730) we figured out that you can set a custom executor to fix this:

.onItem().delayIt()
.onExecutor(ContextAwareScheduler.delegatingTo(Infrastructure.getDefaultWorkerPool()).withCurrentContext())
.by(Duration.ofSeconds(1))

Also see the docs here https://quarkus.io/guides/vertx-reference#use-a-vert-x-context-aware-scheduler

And now you can see both log statements are printed from the event loop thread:

2025-11-06 15:57:20,740 INFO  [org.acm.hib.orm.pan.FruitResource] (vert.x-eventloop-thread-2) Fruit<1>
2025-11-06 15:57:21,745 INFO  [org.acm.hib.orm.pan.FruitResource] (vert.x-eventloop-thread-2) Fruit<1>

This can be very confusing for users while programming, as it happens quite unexpectedly.

Could we somehow make Quarkus either do this automatically for us with the ContextAwareScheduler for delays? Or leverage Vertx somehow under the hood to schedule the delay with Vertx timers on the event loop?

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions