quarkusio / quarkus

Quarkus: Supersonic Subatomic Java.
https://quarkus.io
Apache License 2.0
13.54k stars 2.61k forks source link

Error under load "Detected use of the reactive Session from a different Thread..." #23324

Open mklueh opened 2 years ago

mklueh commented 2 years ago

Describe the bug

I'm using the reactive dependencies and I'm running into a use case, where I need to store events asynchronously when my REST endpoint gets hit, without blocking the REST call and delaying the response.

I thought, well, that's easy. Just use SmallRye Emitter, fire an event and the consumer should handle the storing, while the REST call returns the response. Easier said than done, I'm not getting this simple-sounding example to work without this error when I run a load test with up to 20 req/s (error happens much earlier).

2022-01-31 21:02:35,054 ERROR [com.exa.MyService] (vert.x-eventloop-thread-12) Failed to store event: java.lang.IllegalStateException: 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: 'vert.x-eventloop-thread-11' current Thread: 'vert.x-eventloop-thread-12'
    at org.hibernate.reactive.common.InternalStateAssertions.assertCurrentThreadMatches(InternalStateAssertions.java:46)
    at org.hibernate.reactive.session.impl.ReactiveSessionImpl.threadCheck(ReactiveSessionImpl.java:154)
    at org.hibernate.reactive.session.impl.ReactiveSessionImpl.checkOpen(ReactiveSessionImpl.java:1557)
    at org.hibernate.internal.SessionImpl.contains(SessionImpl.java:2004)
    at org.hibernate.reactive.mutiny.impl.MutinySessionImpl.contains(MutinySessionImpl.java:104)
    at io.quarkus.hibernate.reactive.runtime.ReactiveSessionProducer_ProducerMethod_createMutinySession_1321d110ee9e92bda147899150401e0a136779c7_ClientProxy.contains(Unknown Source)
    at io.quarkus.hibernate.reactive.panache.common.runtime.AbstractJpaOperations.lambda$persist$1(AbstractJpaOperations.java:76)
    at io.smallrye.context.impl.wrappers.SlowContextualFunction.apply(SlowContextualFunction.java:21)
    at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni$UniOnItemTransformToUniProcessor.performInnerSubscription(UniOnItemTransformToUni.java:68)
    at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni$UniOnItemTransformToUniProcessor.onItem(UniOnItemTransformToUni.java:57)
    at io.smallrye.mutiny.operators.uni.builders.UniCreateFromKnownItem$KnownItemSubscription.forward(UniCreateFromKnownItem.java:38)
    at io.smallrye.mutiny.operators.uni.builders.UniCreateFromKnownItem$KnownItemSubscription.access$100(UniCreateFromKnownItem.java:26)
    at io.smallrye.mutiny.operators.uni.builders.UniCreateFromKnownItem.subscribe(UniCreateFromKnownItem.java:23)
    at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
    at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni.subscribe(UniOnItemTransformToUni.java:25)
    at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
    at io.smallrye.mutiny.operators.uni.UniOnItemTransform.subscribe(UniOnItemTransform.java:22)
    at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
    at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni$UniOnItemTransformToUniProcessor.performInnerSubscription(UniOnItemTransformToUni.java:81)
    at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni$UniOnItemTransformToUniProcessor.onItem(UniOnItemTransformToUni.java:57)
    at io.smallrye.mutiny.operators.uni.builders.UniCreateFromKnownItem$KnownItemSubscription.forward(UniCreateFromKnownItem.java:38)
    at io.smallrye.mutiny.operators.uni.builders.UniCreateFromKnownItem$KnownItemSubscription.access$100(UniCreateFromKnownItem.java:26)
    at io.smallrye.mutiny.operators.uni.builders.UniCreateFromKnownItem.subscribe(UniCreateFromKnownItem.java:23)
    at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
    at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni.subscribe(UniOnItemTransformToUni.java:25)
    at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
    at io.smallrye.mutiny.operators.uni.UniOnItemConsume.subscribe(UniOnItemConsume.java:30)
    at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
    at io.smallrye.mutiny.groups.UniSubscribe.withSubscriber(UniSubscribe.java:50)
    at io.smallrye.mutiny.groups.UniSubscribe.with(UniSubscribe.java:111)
    at com.example.MyService.fireForget(MyService.java:20)
    at com.example.MyService_Subclass.fireForget$$superforward1(Unknown Source)
    at com.example.MyService_Subclass$$function$$1.apply(Unknown Source)
    at io.quarkus.arc.impl.AroundInvokeInvocationContext.proceed(AroundInvokeInvocationContext.java:54)
    at io.quarkus.arc.runtime.devconsole.InvocationInterceptor.proceed(InvocationInterceptor.java:62)
    at io.quarkus.arc.runtime.devconsole.InvocationInterceptor.monitor(InvocationInterceptor.java:49)
    at io.quarkus.arc.runtime.devconsole.InvocationInterceptor_Bean.intercept(Unknown Source)
    at io.quarkus.arc.impl.InterceptorInvocation.invoke(InterceptorInvocation.java:41)
    at io.quarkus.arc.impl.AroundInvokeInvocationContext.perform(AroundInvokeInvocationContext.java:41)
    at io.quarkus.arc.impl.InvocationContexts.performAroundInvoke(InvocationContexts.java:32)
    at com.example.MyService_Subclass.fireForget(Unknown Source)
    at com.example.MyService_ClientProxy.fireForget(Unknown Source)
    at com.example.MyService_SmallRyeMessagingInvoker_fireForget_f43d24ab1056a056837479d09bdcf5dd34fec4eb.invoke(Unknown Source)
    at io.smallrye.reactive.messaging.providers.AbstractMediator.invoke(AbstractMediator.java:91)
    at io.smallrye.reactive.messaging.providers.SubscriberMediator.lambda$processMethodReturningVoid$6(SubscriberMediator.java:171)
    at io.smallrye.context.impl.wrappers.SlowContextualSupplier.get(SlowContextualSupplier.java:21)
    at io.smallrye.mutiny.operators.uni.builders.UniCreateFromItemSupplier.subscribe(UniCreateFromItemSupplier.java:28)
    at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
    at io.smallrye.mutiny.operators.uni.UniOnItemOrFailureFlatMap.subscribe(UniOnItemOrFailureFlatMap.java:27)
    at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
    at io.smallrye.mutiny.converters.uni.UniToMultiPublisher$UniToMultiSubscription.request(UniToMultiPublisher.java:63)
    at io.smallrye.mutiny.operators.multi.MultiFlatMapOp$FlatMapInner.onSubscribe(MultiFlatMapOp.java:591)
    at io.smallrye.mutiny.converters.uni.UniToMultiPublisher.subscribe(UniToMultiPublisher.java:24)
    at io.smallrye.mutiny.groups.MultiCreate$1.subscribe(MultiCreate.java:161)
    at io.smallrye.mutiny.operators.multi.MultiFlatMapOp$FlatMapMainSubscriber.onItem(MultiFlatMapOp.java:191)
    at io.smallrye.mutiny.operators.multi.MultiMapOp$MapProcessor.onItem(MultiMapOp.java:50)
    at io.smallrye.mutiny.subscription.MultiSubscriber.onNext(MultiSubscriber.java:61)
    at io.smallrye.mutiny.subscription.SafeSubscriber.onNext(SafeSubscriber.java:98)
    at io.smallrye.mutiny.helpers.HalfSerializer.onNext(HalfSerializer.java:31)
    at io.smallrye.mutiny.helpers.StrictMultiSubscriber.onItem(StrictMultiSubscriber.java:83)
    at io.smallrye.mutiny.operators.multi.MultiOperatorProcessor.onItem(MultiOperatorProcessor.java:89)
    at io.smallrye.mutiny.operators.multi.builders.BufferItemMultiEmitter.drain(BufferItemMultiEmitter.java:118)
    at io.smallrye.mutiny.operators.multi.builders.BufferItemMultiEmitter.emit(BufferItemMultiEmitter.java:34)
    at io.smallrye.mutiny.operators.multi.builders.SerializedMultiEmitter.onItem(SerializedMultiEmitter.java:49)
    at io.smallrye.mutiny.operators.multi.builders.SerializedMultiEmitter.emit(SerializedMultiEmitter.java:139)
    at io.smallrye.reactive.messaging.providers.extension.ThrowingEmitter.emit(ThrowingEmitter.java:63)
    at io.smallrye.reactive.messaging.providers.extension.AbstractEmitter.emit(AbstractEmitter.java:161)
    at io.smallrye.reactive.messaging.providers.extension.EmitterImpl.send(EmitterImpl.java:29)
    at com.example.ExampleResource.lambda$callFetchEntityAndGreetAndLog$2(ExampleResource.java:45)
    at io.smallrye.context.impl.wrappers.SlowContextualFunction.apply(SlowContextualFunction.java:21)
    at io.smallrye.mutiny.groups.UniOnItem.lambda$call$2(UniOnItem.java:79)
    at io.smallrye.context.impl.wrappers.SlowContextualFunction.apply(SlowContextualFunction.java:21)
    at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni$UniOnItemTransformToUniProcessor.performInnerSubscription(UniOnItemTransformToUni.java:68)
    at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni$UniOnItemTransformToUniProcessor.onItem(UniOnItemTransformToUni.java:57)
    at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni$UniOnItemTransformToUniProcessor.onItem(UniOnItemTransformToUni.java:60)
    at io.smallrye.mutiny.operators.uni.builders.DefaultUniEmitter.complete(DefaultUniEmitter.java:36)
    at io.smallrye.mutiny.groups.UniOnNull.lambda$failWith$1(UniOnNull.java:46)
    at io.smallrye.context.impl.wrappers.SlowContextualBiConsumer.accept(SlowContextualBiConsumer.java:21)
    at io.smallrye.mutiny.groups.UniOnItem.lambda$transformToUni$4(UniOnItem.java:178)
    at io.smallrye.context.impl.wrappers.SlowContextualConsumer.accept(SlowContextualConsumer.java:21)
    at io.smallrye.mutiny.operators.uni.builders.UniCreateWithEmitter.subscribe(UniCreateWithEmitter.java:22)
    at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
    at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni$UniOnItemTransformToUniProcessor.performInnerSubscription(UniOnItemTransformToUni.java:81)
    at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni$UniOnItemTransformToUniProcessor.onItem(UniOnItemTransformToUni.java:57)
    at io.smallrye.mutiny.operators.uni.UniOnItemConsume$UniOnItemComsumeProcessor.onItem(UniOnItemConsume.java:43)
    at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni$UniOnItemTransformToUniProcessor.onItem(UniOnItemTransformToUni.java:60)
    at io.smallrye.mutiny.operators.uni.UniOnItemTransform$UniOnItemTransformProcessor.onItem(UniOnItemTransform.java:43)
    at io.smallrye.mutiny.operators.uni.UniOperatorProcessor.onItem(UniOperatorProcessor.java:40)
    at io.smallrye.mutiny.operators.uni.builders.UniCreateFromCompletionStage$CompletionStageUniSubscription.forwardResult(UniCreateFromCompletionStage.java:63)
    at java.base/java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:863)
    at java.base/java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:841)
    at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:510)
    at java.base/java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:2147)
    at io.vertx.core.Future.lambda$toCompletionStage$2(Future.java:360)
    at io.vertx.core.impl.future.FutureImpl$3.onSuccess(FutureImpl.java:141)
    at io.vertx.core.impl.future.FutureBase.emitSuccess(FutureBase.java:60)
    at io.vertx.core.impl.future.FutureImpl.tryComplete(FutureImpl.java:211)
    at io.vertx.core.impl.future.PromiseImpl.tryComplete(PromiseImpl.java:23)
    at io.vertx.sqlclient.impl.QueryResultBuilder.tryComplete(QueryResultBuilder.java:102)
    at io.vertx.sqlclient.impl.QueryResultBuilder.tryComplete(QueryResultBuilder.java:35)
    at io.vertx.core.Promise.complete(Promise.java:66)
    at io.vertx.core.Promise.handle(Promise.java:51)
    at io.vertx.core.Promise.handle(Promise.java:29)
    at io.vertx.core.impl.future.FutureImpl$3.onSuccess(FutureImpl.java:141)
    at io.vertx.core.impl.future.FutureBase.lambda$emitSuccess$0(FutureBase.java:54)
    at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164)
    at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:469)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:503)
    at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:986)
    at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
    at java.base/java.lang.Thread.run(Thread.java:833)

Reactive programming is relatively new to me, so it just could be that I'm missing something obvious I have overlooked in the examples.

Expected behavior

No response

Actual behavior

No response

How to Reproduce?

https://github.com/mklueh/quarkus-reproducer-reactive-hibernate-smallrye-messaging

I've created two load-testing scripts that are using k6 in Docker to test both endpoints. Both will fail.

  1. test-call.sh
  2. test-invoke.sh

Does not matter which, both lead to the same error.

Output of uname -a or ver

No response

Output of java -version

No response

GraalVM version (if different from Java)

No response

Quarkus version or git rev

2.6.3

Build tool (ie. output of mvnw --version or gradlew --version)

No response

Additional information

No response

quarkus-bot[bot] commented 2 years ago

/cc @DavideD, @Sanne, @gavinking

Sanne commented 2 years ago

Thanks for the report! We'll have a look. I didn't check the details but I suspect it might relate to #23300 - let's fix that one first, then verify.

sunildparte commented 2 years ago

I am facing exact same issue when load testing my quarkus application. My application is very similar to this quickstart project - https://github.com/quarkusio/quarkus-quickstarts/tree/main/hibernate-reactive-panache-quickstart. Is there any workaround until https://github.com/quarkusio/quarkus/issues/23300 is fixed?

Sanne commented 2 years ago

I am facing exact same issue when load testing my quarkus application. My application is very similar to this quickstart project - https://github.com/quarkusio/quarkus-quickstarts/tree/main/hibernate-reactive-panache-quickstart. Is there any workaround until #23300 is fixed?

I've described the "workaround" for that issue on it:

mklueh commented 2 years ago

I was running into this problem again, but it seems that it is working at some places, and at others it is not.

workaround:

instead of

FileRef fileRef = new FileRef();

Uni<PanacheEntityBase>  uni = Panache.withTransaction(fileRef::persist)

//or

Uni<FileRef>  uni = Panache.withTransaction(()->fileRefRepository.persist(fileRef))

using this

FileRef fileRef = new FileRef();

Uni<FileRef> uni = sessionFactory.withTransaction(session -> session.persist(fileRef).onItem().transform(unused -> fileRef));

The workaround really helps, but is there any progress with this issue so far already @Sanne ?

Sanne commented 2 years ago

hi @mklueh in that particular case I suspect you're hitting a very similar issue (but not the same) with scopes in reactive messaging. This should be fixed in Quarkus 2.7.2 - could you try it?

bartwinski commented 2 years ago

Hello @Sanne with the quarkus 2.7.5 Final we still facing this issue under load. Especially directly after quarkus startup. Without high load it works fine. We are using reactive-hibernate with Postgres We are using following approach: Panache.withTransaction {entity.persist()} Using sessionFactory.withTransaction works also not. The same exception is thrown: Failed to store event: java.lang.IllegalStateException: 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: 'vert.x-eventloop-thread-11' current Thread: 'vert.x-eventloop-thread-12'

zuochangqin commented 2 years ago

Is there any update on this topic? Do I have to wrap every method that operates on the database with Panache. WithTransaction? Reactive Hibernate is not stable, and often causes errors.The quarkus version I use is 2.8.2.final.

Sanne commented 2 years ago

Let me explain, Hibernate Reactive by design requires all operations to be executed from the same thread.

The exception "java.lang.IllegalStateException: HR000069: Detected use of the reactive Session from a different Thread than ..." literally means that we've detected illegal use of it, and we're throwing an exception on purpose so that integration problems can be detected (such integration problems would otherwise most likely lead to more serious issues, such as data inconsistencies being written).

If you have such issues, you're using it in the wrong context. If you can't strictly guarantee that your application is fully reactive and that each transaction is constrained within the same unique thread, you shouldn't use it; consider using Hiberante ORM blocking, which is more suited for non-blocking designs.

The reason Panache.withTransaction helps is because it offloads the entire "work" definition onto a vert.x worker thread; so even if you were running it on the wrong thread it will first switch to the right thread, then execute it correctly. This is not optimal in terms of efficiency, but helps straighetning integration with other components.

Also, please use the Mutiny based API of Hibernate Reactive. When using CompletionStage it gets surprisingly tricky to get the threading model correct.

Reactive Hibernate is not stable, and often causes errors.

Well as I mentioned we throw these exceptions on purpose - not because it's unstable but most likely because it's not being used correctly.

I'll have another look at the reproducer of this issue - pretty sure something is wrong in the integration. Other people commenting here... please open a different issue and attach a reproducer, I can't help you otherwise - sorry :/

DavideD commented 2 years ago

I've tested the original testcase with Quarkus 2.9.2 and I cannot see the error anymore.

Still, I'm not sure how one is supposed to implement this use-case.

This is what the test case is trying to achieve:

  1. Http get to a Rest service
  2. The service look for an entity in the db by id
  3. When the entity is found emit an event in a channel
  4. The service listening to the channel will create a new event in the db

Point 4 is implemented this way:

@Slf4j
@ApplicationScoped
public class MyService {

    @Incoming(Event.FIRE_AND_FORGET)
    public void fireForget(Event event) {
        Panache.withTransaction(event::persist)
                .onFailure().invoke(throwable -> log.error("Failed to store event", throwable))
                .subscribe().with(panacheEntityBase -> {
                });
    }
}

Is this the right approach to use?

When I've upgraded to Quarkus 2.9.2 I had to add @ActivateRequestContext:

@Slf4j
@ApplicationScoped
@ActivateRequestContext 
public class MyService {

    @Incoming(Event.FIRE_AND_FORGET)
    public void fireForget(Event event) {
        Panache.withTransaction( event::persist )
                .onFailure().invoke( throwable -> log.error( "Failed to store event", throwable ) )
                .subscribe().with( System.out::println, System.err::println );
    }
}

I'm asking because it doesn't seem to work and I get the error

2022-05-26 13:43:02,487 ERROR [com.exa.MyService] (vert.x-eventloop-thread-1) Failed to store event: java.lang.IllegalStateException: HR000060: Session is closed                                                    

I think the error the issue is referring to has been solved but it would be nice to fix the testcase so that it works

inngvar commented 1 year ago

"workaround" you can try:

DavideD commented 1 year ago

I'm not sure that's the right approach. Probably, the session closed error happens because the session is closed when returning from fireAndForget. But because the content is async, it might happen that it's closed too soon, before withTransaction is even executed.

I think a better solution would is to use the Hibernate Session factory directly. But I need to test it.

DavideD commented 1 year ago

If I use the Hibernate Reactive session factory, I see this error:

022-09-20 09:01:03,807 ERROR [org.jbo.res.rea.com.cor.AbstractResteasyReactiveContext] (vert.x-eventloop-thread-2) Request failed: java.lang.IllegalStateException: The current operation requires a safe (isolated) Vert.x sub-context, but the current context hasn't been flagged as such. You can still use Hibernate Reactive, you just need to avoid using the methods which implicitly require accessing the stateful context, such as MutinySessionFactory#withTransaction and #withSession.
        at io.quarkus.vertx.core.runtime.context.VertxContextSafetyToggle.checkIsSafe(VertxContextSafetyToggle.java:89)
        at io.quarkus.vertx.core.runtime.context.VertxContextSafetyToggle.validateContextIfExists(VertxContextSafetyToggle.java:72)
        at io.quarkus.hibernate.reactive.runtime.customized.CheckingVertxContext.get(CheckingVertxContext.java:46)
        at org.hibernate.reactive.mutiny.impl.MutinySessionFactoryImpl.withSession(MutinySessionFactoryImpl.java:189)
DavideD commented 1 year ago

This implementation should work though:

@Slf4j
@ApplicationScoped
public class MyService {

    @Inject
    Mutiny.SessionFactory sf;

    @Incoming(Event.FIRE_AND_FORGET)
    public void fireForget(Event event) {
        sf.openSession().chain(session -> session
                        .withTransaction( tx -> session.persist( event ) )
                        .eventually( session::close )
                )
                .onFailure().invoke(throwable -> log.error("Failed to store event", throwable))
                .subscribe().with(panacheEntityBase -> {
                });
    }
}
kavishkamk commented 1 year ago

Hi. I am facing the same issue. I am currently using 2.16.5.Final. in new versions is this solved? or I have to go with some kind of blocking operation as suggested.

DavideD commented 1 year ago

@kavishkamk I would suggest to upgrade and test the application with the latest version

devorgpl commented 10 months ago

Same error with "delete", OpenJDK 21

        <quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
        <quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
        <quarkus.platform.version>3.4.3</quarkus.platform.version>
        <surefire-plugin.version>3.1.2</surefire-plugin.version>
        <compiler-plugin.version>3.11.0</compiler-plugin.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <assertj.version>3.22.0</assertj.version>

Steps to reproduce: git clone https://github.com/quarkusio/quarkus-quickstarts && cd quarkus-quickstarts/hibernate-reactive-panache-quickstart

add more samples in import.sql

INSERT INTO fruit(id, name) VALUES (1, 'Cherry');
INSERT INTO fruit(id, name) VALUES (2, 'Apple');
INSERT INTO fruit(id, name) VALUES (3, 'Banana');
INSERT INTO fruit(id, name) VALUES (4, 'Banana1');
INSERT INTO fruit(id, name) VALUES (5, 'Banana2');
INSERT INTO fruit(id, name) VALUES (6, 'Banana3');
INSERT INTO fruit(id, name) VALUES (7, 'Banana4');
INSERT INTO fruit(id, name) VALUES (8, 'Banana5');
INSERT INTO fruit(id, name) VALUES (9, 'Banana6');
INSERT INTO fruit(id, name) VALUES (10, 'Banana7');
INSERT INTO fruit(id, name) VALUES (11, 'Banana8');
INSERT INTO fruit(id, name) VALUES (12, 'Banana9');
INSERT INTO fruit(id, name) VALUES (13, 'Banana11');
INSERT INTO fruit(id, name) VALUES (14, 'Banana12');
INSERT INTO fruit(id, name) VALUES (15, 'Banana14');
INSERT INTO fruit(id, name) VALUES (16, 'Banana15');
INSERT INTO fruit(id, name) VALUES (17, 'Banana16');
INSERT INTO fruit(id, name) VALUES (18, 'Banana17');
INSERT INTO fruit(id, name) VALUES (19, 'Banana88');
ALTER SEQUENCE fruit_seq RESTART WITH 20;

Start server: mvn quarkus:dev

run test:

for i in {1..19}
 do
curl -X DELETE "http://localhost:8080/fruits/${i}"&
done

Result:

$ /bin/bash quarkus-quickstarts/hibernate-reactive-panache-quickstart/delete.sh
$ {"exceptionType":"org.hibernate.HibernateException","code":500,"error":"java.lang.IllegalStateException: 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 [138]: 'vert.x-eventloop-thread-3' current Thread [137]: 'vert.x-eventloop-thread-2'"}

and server exception:

Hibernate: 
    select
        f1_0.id,
        f1_0.name 
    from
        Fruit f1_0 
    where
        f1_0.id=$1

2023-10-16 04:18:18,103 ERROR [org.acm.hib.orm.pan.FruitResource] (vert.x-eventloop-thread-3) Failed to handle request: org.hibernate.HibernateException: java.lang.IllegalStateException: 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 [138]: 'vert.x-eventloop-thread-3' current Thread [137]: 'vert.x-eventloop-thread-2'
        at org.hibernate.reactive.session.impl.ReactiveExceptionConverter.convert(ReactiveExceptionConverter.java:28)
        at org.hibernate.reactive.session.impl.ReactiveSessionImpl.lambda$doFlush$27(ReactiveSessionImpl.java:994)
        at java.base/java.util.concurrent.CompletableFuture.uniHandle(CompletableFuture.java:934)
        at java.base/java.util.concurrent.CompletableFuture$UniHandle.tryFire(CompletableFuture.java:911)
        at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:510)
        at java.base/java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:2179)
        at org.hibernate.reactive.util.async.impl.AsyncTrampoline$TrampolineInternal.unroll(AsyncTrampoline.java:131)
        at org.hibernate.reactive.util.async.impl.AsyncTrampoline$TrampolineInternal.lambda$unroll$0(AsyncTrampoline.java:126)
        at java.base/java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:863)
        at java.base/java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:841)
        at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:510)
        at java.base/java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:2179)
        at org.hibernate.reactive.persister.entity.mutation.ReactiveDeleteCoordinator.complete(ReactiveDeleteCoordinator.java:198)
        at java.base/java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:863)
        at java.base/java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:841)
        at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:510)
        at java.base/java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:2179)
        at io.vertx.core.Future.lambda$toCompletionStage$3(Future.java:536)
        at io.vertx.core.impl.future.FutureImpl$3.onSuccess(FutureImpl.java:141)
        at io.vertx.core.impl.future.FutureBase.emitSuccess(FutureBase.java:60)
        at io.vertx.core.impl.future.FutureImpl.tryComplete(FutureImpl.java:211)
        at io.vertx.core.impl.future.PromiseImpl.tryComplete(PromiseImpl.java:23)
        at io.vertx.sqlclient.impl.QueryResultBuilder.tryComplete(QueryResultBuilder.java:88)
        at io.vertx.sqlclient.impl.QueryResultBuilder.tryComplete(QueryResultBuilder.java:32)
        at io.vertx.core.Promise.complete(Promise.java:66)
        at io.vertx.core.Promise.handle(Promise.java:51)
        at io.vertx.core.Promise.handle(Promise.java:29)
        at io.vertx.core.impl.future.FutureImpl$3.onSuccess(FutureImpl.java:141)
        at io.vertx.core.impl.future.FutureBase.emitSuccess(FutureBase.java:60)
        at io.vertx.core.impl.future.FutureImpl.tryComplete(FutureImpl.java:211)
        at io.vertx.core.impl.future.PromiseImpl.tryComplete(PromiseImpl.java:23)
        at io.vertx.core.impl.future.PromiseImpl.onSuccess(PromiseImpl.java:49)
        at io.vertx.core.impl.future.PromiseImpl.handle(PromiseImpl.java:41)
        at io.vertx.sqlclient.impl.TransactionImpl.lambda$wrap$0(TransactionImpl.java:72)
        at io.vertx.core.impl.future.FutureImpl$3.onSuccess(FutureImpl.java:141)
        at io.vertx.core.impl.future.FutureBase.lambda$emitSuccess$0(FutureBase.java:54)
        at io.netty.util.concurrent.AbstractEventExecutor.runTask(AbstractEventExecutor.java:173)
        at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:166)
        at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:470)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:566)
        at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997)
        at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.base/java.lang.Thread.run(Thread.java:1583)
Caused by: java.lang.IllegalStateException: 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 [138]: 'vert.x-eventloop-thread-3' current Thread [137]: 'vert.x-eventloop-thread-2'
        at org.hibernate.reactive.common.InternalStateAssertions.assertCurrentThreadMatches(InternalStateAssertions.java:46)
        at org.hibernate.reactive.session.impl.ReactiveSessionImpl.threadCheck(ReactiveSessionImpl.java:183)
        at org.hibernate.reactive.session.impl.ReactiveSessionImpl.checkOpen(ReactiveSessionImpl.java:1670)
        at org.hibernate.internal.AbstractSharedSessionContract.checkOpenOrWaitingForAutoClose(AbstractSharedSessionContract.java:447)
        at org.hibernate.internal.SessionImpl.checkOpenOrWaitingForAutoClose(SessionImpl.java:616)
        at org.hibernate.internal.SessionImpl.getPersistenceContext(SessionImpl.java:1825)
        at org.hibernate.reactive.event.impl.AbstractReactiveFlushingEventListener.lambda$performExecutions$0(AbstractReactiveFlushingEventListener.java:65)
        at java.base/java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:863)
        at java.base/java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:841)
        ... 40 more
devorgpl commented 10 months ago

Exception is random. This workaround seems to work:

@Entity
@Cacheable
@NamedQueries({
        @NamedQuery(name = "Fruit.deleteById", query = "delete from Fruit p where p.id = ?1")
})
public class Fruit extends PanacheEntity {
[...]
    public static Uni<Boolean> deleteById(Long id) {
        return delete("#Fruit.deleteById", id).map(t -> t > 0);
    }
}
zivkovic commented 10 months ago

I have the same problem. Simply performance testing the repository "deleteById" method, which is autogenerated by quarkus throws this error. If I replace the implementation with the code below, then delete works as it should (thanks @devorgpl, I have no idea how you managed to discover this). This tells me the problem seems to be in quarkus panache implementation itself. Debugging this is a real PITA.

override fun deleteById(id: UUID): Uni<Boolean> {
    return delete("id = ?1", id).map { result -> result > 0 }
}
DavideD commented 10 months ago

I'm not sure why it fails, but using @WithTransaction seems to fix the issue:

    @DELETE
    @Path("{id}")
    @WithTransaction
    public Uni<Response> delete(Long id) {
        return Fruit.deleteById(id)
                .map(deleted -> deleted
                        ? Response.ok().status(NO_CONTENT).build()
                        : Response.ok().status(NOT_FOUND).build());
    }

I'm still looking into this though

DavideD commented 10 months ago

Nevermind, using the annotation doesn't solve the issue

DavideD commented 10 months ago

@mkouba I think we might need your help with this issue

mkouba commented 10 months ago

@mkouba I think we might need your help with this issue

@DavideD I'm not sure I will be of any help here - the stack trace from the hibernate-reactive-panache-quickstart does not contain anything related to HR Panache. Am I missing somethig?

DavideD commented 10 months ago

I don't think it's Panache, but it seems that the session is created in one thread and then used in another. I was wondering if you might have some word of wisdom, or maybe there's an annotation that I'm not aware about that could help.

mkouba commented 10 months ago

I don't think it's Panache, but it seems that the session is created in one thread and then used in another. I was wondering if you might have some word of wisdom, or maybe there's an annotation that I'm not aware about that could help.

I'm not aware of any annotation that could help here. It seems that the session is opened on the thread that handles the request, in this particular case on the thread that executed the FruitResource.delete() method. But for some reason the flush operation seems to be executed on a different thread...

DavideD commented 10 months ago

I wonder if it's because the deleteById is split into a find and then a delete operation, instead of being a single one. Anyway, I will continue looking.

mkouba commented 10 months ago

I wonder if it's because the deleteById is split into a find and then a delete operation, instead of being a single one. Anyway, I will continue looking.

Well, it should not be a problem since the operations are executed within a single transaction, right?

DavideD commented 10 months ago

Yes, it shouldn't. Unless we are missing something.

DavidMachacek commented 10 months ago

Same problem here fun getAllPets(): Uni<List<PetDTO>> { logger.info { "operation=getAllPetsBegin, layer=service" } val criteriaBuilder = sessionFactory.criteriaBuilder val query = criteriaBuilder.createQuery(PetDTO::class.java) //for some reason, root query must be specified, even if not unused val root = query.from(PetDTO::class.java) return sessionFactory.withSession { session -> logger.info { "operation=getAllPetsBegin, layer=hibernate" } session.createQuery(query).resultList .onItem().ifNull().continueWith{listOf(PetDTO())} .onItem().call(session::flush) .also { logger.info { "operation=getAllPetsEnd, layer=hibernate, result=complete" } } }.also { logger.info { "operation=getAllPetsEnd, layer=service" } } }

Dependencies: vertx-stack-depchain:4.1.8 hibernate-reactive-core:2.0.6.Final

ErrorStack: `2023-11-07T08:43:19.502Z INFO 1 --- [ntloop-thread-0] com.sgc.appd.vertxdemo.PetService : operation=getAllPetsEnd, layer=hibernate, result=complete [Hibernate] select p1_0.id,p1_0.name,p1_0.type from PetDTO p1_0 2023-11-07T08:43:19.504Z INFO 1 --- [ntloop-thread-0] com.sgc.appd.vertxdemo.PetHandlers : operation=getAllEnd, layer=handler [-- Mutiny had to drop the following exception --] Exception received by: io.smallrye.mutiny.infrastructure.Infrastructure.handleDroppedException(Infrastructure.java:295) io.smallrye.mutiny.CompositeException: Multiple exceptions caught:

[Exception 1] java.lang.IllegalStateException: 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 [40]: 'vert.x-eventloop-thread-0' current Thread [47]: 'vert.x-eventloop-thread-1'
at io.smallrye.mutiny.groups.UniOnItemOrFailure.lambda$call$1(UniOnItemOrFailure.java:75)
at io.smallrye.mutiny.operators.uni.UniOnItemOrFailureFlatMap$UniOnItemOrFailureFlatMapProcessor.performInnerSubscription(UniOnItemOrFailureFlatMap.java:86)
at io.smallrye.mutiny.operators.uni.UniOnItemOrFailureFlatMap$UniOnItemOrFailureFlatMapProcessor.onFailure(UniOnItemOrFailureFlatMap.java:65)
at io.smallrye.mutiny.operators.uni.UniOperatorProcessor.onFailure(UniOperatorProcessor.java:55)
at io.smallrye.mutiny.helpers.EmptyUniSubscription.propagateFailureEvent(EmptyUniSubscription.java:40)
at io.smallrye.mutiny.operators.uni.builders.UniCreateFromCompletionStage.subscribe(UniCreateFromCompletionStage.java:26)
at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
at io.smallrye.mutiny.operators.uni.UniRunSubscribeOn.lambda$subscribe$0(UniRunSubscribeOn.java:27)
at org.hibernate.reactive.context.impl.VertxContext.execute(VertxContext.java:91)
at io.smallrye.mutiny.operators.uni.UniRunSubscribeOn.subscribe(UniRunSubscribeOn.java:25)
at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
at io.smallrye.mutiny.operators.uni.UniOnItemOrFailureFlatMap.subscribe(UniOnItemOrFailureFlatMap.java:27)
at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
at io.smallrye.mutiny.operators.uni.UniOnItemOrFailureFlatMap$UniOnItemOrFailureFlatMapProcessor.performInnerSubscription(UniOnItemOrFailureFlatMap.java:99)
at io.smallrye.mutiny.operators.uni.UniOnItemOrFailureFlatMap$UniOnItemOrFailureFlatMapProcessor.onFailure(UniOnItemOrFailureFlatMap.java:65)
at io.smallrye.mutiny.operators.uni.UniOnItemOrFailureConsume$UniOnItemOrFailureConsumeProcessor.onFailure(UniOnItemOrFailureConsume.java:46)
at io.smallrye.mutiny.operators.uni.UniOperatorProcessor.onFailure(UniOperatorProcessor.java:55)
at io.smallrye.mutiny.operators.uni.UniOperatorProcessor.onFailure(UniOperatorProcessor.java:55)
at io.smallrye.mutiny.operators.uni.UniOperatorProcessor.onFailure(UniOperatorProcessor.java:55)
at io.smallrye.mutiny.operators.uni.UniOperatorProcessor.onFailure(UniOperatorProcessor.java:55)
at io.smallrye.mutiny.operators.uni.builders.UniCreateFromCompletionStage$CompletionStageUniSubscription.forwardResult(UniCreateFromCompletionStage.java:58)
at java.base/java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:863)
at java.base/java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:841)
at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:510)
at java.base/java.util.concurrent.CompletableFuture.completeExceptionally(CompletableFuture.java:2162)
at org.hibernate.reactive.util.async.impl.AsyncTrampoline$TrampolineInternal.lambda$unroll$0(AsyncTrampoline.java:123)
at java.base/java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:863)
at java.base/java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:841)
at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:510)
at java.base/java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:2147)
at io.vertx.core.Future.lambda$toCompletionStage$2(Future.java:360)
at io.vertx.core.impl.future.FutureImpl$3.onSuccess(FutureImpl.java:141)
at io.vertx.core.impl.future.FutureBase.emitSuccess(FutureBase.java:60)
at io.vertx.core.impl.future.FutureImpl.tryComplete(FutureImpl.java:211)
at io.vertx.core.impl.future.PromiseImpl.tryComplete(PromiseImpl.java:23)
at io.vertx.sqlclient.impl.QueryResultBuilder.tryComplete(QueryResultBuilder.java:102)
at io.vertx.sqlclient.impl.QueryResultBuilder.tryComplete(QueryResultBuilder.java:35)
at io.vertx.core.Promise.complete(Promise.java:66)
at io.vertx.core.Promise.handle(Promise.java:51)
at io.vertx.core.Promise.handle(Promise.java:29)
at io.vertx.core.impl.future.FutureImpl$3.onSuccess(FutureImpl.java:141)
at io.vertx.core.impl.future.FutureBase.emitSuccess(FutureBase.java:60)
at io.vertx.core.impl.future.FutureImpl.tryComplete(FutureImpl.java:211)
at io.vertx.core.impl.future.PromiseImpl.tryComplete(PromiseImpl.java:23)
at io.vertx.core.impl.future.PromiseImpl.onSuccess(PromiseImpl.java:49)
at io.vertx.core.impl.future.PromiseImpl.handle(PromiseImpl.java:41)
at io.vertx.core.impl.future.PromiseImpl.handle(PromiseImpl.java:23)
at io.vertx.sqlclient.impl.command.CommandResponse.fire(CommandResponse.java:46)
at io.vertx.sqlclient.impl.SocketConnectionBase.handleMessage(SocketConnectionBase.java:287)
at io.vertx.sqlclient.impl.SocketConnectionBase.lambda$init$0(SocketConnectionBase.java:99)
at io.vertx.core.net.impl.NetSocketImpl.lambda$new$1(NetSocketImpl.java:97)
at io.vertx.core.streams.impl.InboundBuffer.handleEvent(InboundBuffer.java:240)
at io.vertx.core.streams.impl.InboundBuffer.write(InboundBuffer.java:130)
at io.vertx.core.net.impl.NetSocketImpl.lambda$handleMessage$9(NetSocketImpl.java:390)
at io.vertx.core.impl.EventLoopContext.emit(EventLoopContext.java:50)
at io.vertx.core.impl.ContextImpl.emit(ContextImpl.java:274)
at io.vertx.core.impl.EventLoopContext.emit(EventLoopContext.java:22)
at io.vertx.core.net.impl.NetSocketImpl.handleMessage(NetSocketImpl.java:389)
at io.vertx.core.net.impl.ConnectionBase.read(ConnectionBase.java:155)
at io.vertx.core.net.impl.VertxHandler.channelRead(VertxHandler.java:154)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:436)
at io.vertx.mssqlclient.impl.codec.TdsMessageEncoder.lambda$write$0(TdsMessageEncoder.java:63)
at io.vertx.mssqlclient.impl.codec.MSSQLCommandCodec.complete(MSSQLCommandCodec.java:199)
at io.vertx.mssqlclient.impl.codec.MSSQLCommandCodec.handleDecodingComplete(MSSQLCommandCodec.java:189)
at io.vertx.mssqlclient.impl.codec.MSSQLCommandCodec.decode(MSSQLCommandCodec.java:83)
at io.vertx.mssqlclient.impl.codec.TdsMessageDecoder.decodeMessage(TdsMessageDecoder.java:65)
at io.vertx.mssqlclient.impl.codec.TdsMessageDecoder.channelRead(TdsMessageDecoder.java:43)
at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:251)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:324)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:296)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1371)
at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1234)
at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1283)
at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:507)
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:446)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:276)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:722)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:658)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:584)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:496)
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:986)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:833)
Suppressed: java.lang.IllegalStateException: 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 [40]: 'vert.x-eventloop-thread-0' current Thread [47]: 'vert.x-eventloop-thread-1'
    at org.hibernate.reactive.common.InternalStateAssertions.assertCurrentThreadMatches(InternalStateAssertions.java:46)
    at org.hibernate.reactive.session.impl.ReactiveSessionImpl.threadCheck(ReactiveSessionImpl.java:183)
    at org.hibernate.reactive.session.impl.ReactiveSessionImpl.checkOpen(ReactiveSessionImpl.java:1670)
    at org.hibernate.internal.AbstractSharedSessionContract.checkOpenOrWaitingForAutoClose(AbstractSharedSessionContract.java:447)
    at org.hibernate.internal.SessionImpl.checkOpenOrWaitingForAutoClose(SessionImpl.java:616)
    at org.hibernate.internal.SessionImpl.closeWithoutOpenChecks(SessionImpl.java:410)
    at org.hibernate.internal.SessionImpl.close(SessionImpl.java:397)
    at org.hibernate.reactive.session.impl.ReactiveSessionImpl.reactiveClose(ReactiveSessionImpl.java:1622)
    at io.smallrye.mutiny.operators.uni.builders.UniCreateFromCompletionStage.subscribe(UniCreateFromCompletionStage.java:24)
    ... 95 more

Caused by: java.lang.IllegalStateException: 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 [40]: 'vert.x-eventloop-thread-0' current Thread [47]: 'vert.x-eventloop-thread-1' at org.hibernate.reactive.common.InternalStateAssertions.assertCurrentThreadMatches(InternalStateAssertions.java:46) at org.hibernate.reactive.session.impl.ReactiveSessionImpl.threadCheck(ReactiveSessionImpl.java:183) at org.hibernate.reactive.session.impl.ReactiveSessionImpl.checkOpen(ReactiveSessionImpl.java:1670) at org.hibernate.internal.AbstractSharedSessionContract.checkOpenOrWaitingForAutoClose(AbstractSharedSessionContract.java:447) at org.hibernate.internal.SessionImpl.checkOpenOrWaitingForAutoClose(SessionImpl.java:616) at org.hibernate.internal.SessionImpl.instantiate(SessionImpl.java:1464) at org.hibernate.sql.results.graph.entity.AbstractEntityInitializer.instantiateEntity(AbstractEntityInitializer.java:687) at org.hibernate.sql.results.graph.entity.AbstractEntityInitializer.resolveEntityInstance(AbstractEntityInitializer.java:680) at org.hibernate.sql.results.graph.entity.AbstractEntityInitializer.resolveInstance(AbstractEntityInitializer.java:646) at org.hibernate.sql.results.graph.entity.AbstractEntityInitializer.resolveEntityInstance(AbstractEntityInitializer.java:537) at org.hibernate.sql.results.graph.entity.AbstractEntityInitializer.resolveInstance(AbstractEntityInitializer.java:397) at org.hibernate.reactive.sql.results.graph.entity.ReactiveAbstractEntityInitializer.reactiveResolveInstance(ReactiveAbstractEntityInitializer.java:79) at org.hibernate.reactive.sql.results.internal.ReactiveInitializersList.lambda$resolveInstances$1(ReactiveInitializersList.java:86) at org.hibernate.reactive.util.impl.CompletionStages.lambda$loop$2(CompletionStages.java:178) at org.hibernate.reactive.util.impl.CompletionStages.lambda$loop$7(CompletionStages.java:417) at org.hibernate.reactive.util.impl.CompletionStages$ArrayLoop.next(CompletionStages.java:491) at org.hibernate.reactive.util.async.impl.AsyncTrampoline.lambda$asyncWhile$1(AsyncTrampoline.java:215) at org.hibernate.reactive.util.async.impl.AsyncTrampoline$TrampolineInternal.unroll(AsyncTrampoline.java:121) at org.hibernate.reactive.util.async.impl.AsyncTrampoline$TrampolineInternal.trampoline(AsyncTrampoline.java:102) at org.hibernate.reactive.util.async.impl.AsyncTrampoline.asyncWhile(AsyncTrampoline.java:197) at org.hibernate.reactive.util.async.impl.AsyncTrampoline.asyncWhile(AsyncTrampoline.java:215) at org.hibernate.reactive.util.impl.CompletionStages.loop(CompletionStages.java:418) at org.hibernate.reactive.util.impl.CompletionStages.loop(CompletionStages.java:389) at org.hibernate.reactive.util.impl.CompletionStages.loop(CompletionStages.java:178) at org.hibernate.reactive.sql.results.internal.ReactiveInitializersList.resolveInstances(ReactiveInitializersList.java:84) at org.hibernate.reactive.sql.results.internal.ReactiveStandardRowReader.coordinateInitializers(ReactiveStandardRowReader.java:125) at org.hibernate.reactive.sql.results.internal.ReactiveStandardRowReader.reactiveReadRow(ReactiveStandardRowReader.java:59) at org.hibernate.reactive.sql.results.spi.ReactiveListResultsConsumer.lambda$addToResultsSupplier$5(ReactiveListResultsConsumer.java:134) at org.hibernate.reactive.sql.results.spi.ReactiveListResultsConsumer.lambda$consume$1(ReactiveListResultsConsumer.java:108) at java.base/java.util.concurrent.CompletableFuture$UniCompose.tryFire(CompletableFuture.java:1150) ... 73 more [------------------------------------------------] java.net.SocketException: Connection reset at java.base/sun.nio.ch.SocketChannelImpl.throwConnectionReset(SocketChannelImpl.java:394) at java.base/sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:426) at io.netty.buffer.PooledByteBuf.setBytes(PooledByteBuf.java:253) at io.netty.buffer.AbstractByteBuf.writeBytes(AbstractByteBuf.java:1132) at io.netty.channel.socket.nio.NioSocketChannel.doReadBytes(NioSocketChannel.java:350) at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:151) at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:722) at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:658) at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:584) at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:496) at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:986) at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) at java.base/java.lang.Thread.run(Thread.java:833)`

f4lco commented 1 month ago

We do think that the bug is still relevant 2.5 years later, and might have caused / contributed to https://github.com/quarkusio/quarkus/issues/41240#issuecomment-2276357106. With Quarkus 3.8.5, we get the same stack traces, and the proposed workarounds successfully mitigate the error.