Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"Hibernate Reactive Panache requires a safe (isolated) Vert.x sub-context, but the current context hasn't been flagged as such." when using Smallrye Messaging #35106

Open
mklueh opened this issue Jul 31, 2023 · 6 comments
Labels

Comments

@mklueh
Copy link
Contributor

mklueh commented Jul 31, 2023

Describe the bug

Scenario: EntityA get's persisted, notification with entity is sent through message channel, receiver creates EntityB and links it to EntityA

This leads to the following error:

erResourceTest > testCreateUser() STANDARD_ERROR
    Jul 31, 2023 7:37:55 AM io.smallrye.reactive.messaging.providers.AbstractMediator invoke
    ERROR: SRMSG00200: The method com.example.EntityAService#onUserRegistrationConfirmed has thrown an exception
    java.lang.IllegalStateException: Hibernate Reactive Panache requires a safe (isolated) Vert.x sub-context, but the current context hasn't been flagged as such.
        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.panache.common.runtime.SessionOperations.vertxContext(SessionOperations.java:183)
        at io.quarkus.hibernate.reactive.panache.common.runtime.SessionOperations.withSession(SessionOperations.java:112)
        at io.quarkus.hibernate.reactive.panache.common.runtime.WithSessionInterceptor.intercept(WithSessionInterceptor.java:20)
        at io.quarkus.hibernate.reactive.panache.common.runtime.WithSessionInterceptor_Bean.intercept(Unknown Source)
        at io.quarkus.arc.impl.InterceptorInvocation.invoke(InterceptorInvocation.java:42)
        at io.quarkus.arc.impl.AroundInvokeInvocationContext.perform(AroundInvokeInvocationContext.java:30)
        at io.quarkus.arc.impl.InvocationContexts.performAroundInvoke(InvocationContexts.java:27)
        at com.example.EntityAService_Subclass.onUserRegistrationConfirmed(Unknown Source)
        at com.example.EntityAService_ClientProxy.onUserRegistrationConfirmed(Unknown Source)
        at com.example.EntityAService_SmallRyeMessagingInvoker_onUserRegistrationConfirmed_3712669874522feb4afaa8774dd5fa51e4e2f384.invoke(Unknown Source)
        at io.smallrye.reactive.messaging.providers.AbstractMediator.invoke(AbstractMediator.java:136)
        at io.smallrye.reactive.messaging.providers.AbstractMediator.lambda$invokeOnMessageContext$8(AbstractMediator.java:144)
        at io.smallrye.reactive.messaging.providers.locals.LocalContextMetadata.lambda$invokeOnMessageContext$0(LocalContextMetadata.java:34)
        at io.smallrye.reactive.messaging.providers.locals.LocalContextMetadata.lambda$invokeOnMessageContext$1(LocalContextMetadata.java:53)
        at io.smallrye.reactive.messaging.providers.helpers.VertxContext.lambda$runOnContext$0(VertxContext.java:26)
        at io.vertx.core.impl.ContextInternal.dispatch(ContextInternal.java:264)
        at io.vertx.core.impl.ContextInternal.dispatch(ContextInternal.java:246)
        at io.vertx.core.impl.EventLoopContext.lambda$runOnContext$0(EventLoopContext.java:43)
        at io.netty.util.concurrent.AbstractEventExecutor.runTask(AbstractEventExecutor.java:174)
        at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:167)
        at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:470)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:569)
        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:1589)

I'm not sure if it is a Quarkus / Vert.X bug or if I'm missing something in my implementation.

The message is sent from within a transaction, and as I'm not using the @Broadcast annotation, I guess the transaction might still be open on the receiver-side or at least the same session is getting used. Is this true?

Are there any best / bad practices for using transactions / sessions accross a message bus?

Is also related to #34291 but decided to open a new issue with the reproducer that is not kafka-related

Expected behavior

To save the second entity without issues.

Actual behavior

No response

How to Reproduce?

https://github.com/mklueh/quarkus-reactive-reproducer-context-not-flagged

Run the test inside the test package

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

No response

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

No response

Additional information

No response

@mklueh mklueh added the kind/bug Something isn't working label Jul 31, 2023
@quarkus-bot
Copy link

quarkus-bot bot commented Jul 31, 2023

/cc @DavideD (hibernate-reactive), @FroMage (panache), @Ladicek (smallrye), @Sanne (hibernate-reactive), @gavinking (hibernate-reactive), @jmartisk (smallrye), @loicmathieu (panache), @phillip-kruger (smallrye), @radcortez (smallrye)

@FroMage
Copy link
Member

FroMage commented Aug 14, 2023

Sounds ike a question for @cescoffier

@cescoffier
Copy link
Member

It's because you use an emitter with an "in-process/in-memory" channel. The message is processed on another duplicated context, which is not marked as safe by default (on purpose, as we can't know).
Use the latest Quarkus; you can use the io.quarkus.vertx.SafeVertxContext annotation:

    @SafeVertxContext
    @WithSession
    @Incoming(Events.USER_REGISTRATION_CONFIRMED)
    public Uni<EntityA> onUserRegistrationConfirmed(User user) {   
        return createEntityAAndLinkToUser(user.id)
                .onItem().invoke(link -> log.info("EntityA created and linked"));
    }

@mklueh
Copy link
Contributor Author

mklueh commented Aug 21, 2023

@cescoffier thanks for the explanation.

So let's say you are using Kafka as an emitter, the @SafeVertxContext would not be needed then?
Would this annotation even hurt in that case or can we safely just put it on every receiver?
If so, can't you just assume every receiver is safe by default instead of requiring the then-verbose annotation?

Edit: I don't have the annotation with Quarkus 3.2.4

@cescoffier
Copy link
Member

cescoffier commented Aug 21, 2023

The annotation is in Quarkus 3.3. In the previous version, you have an API doing the same (VertxContextSafetyToggle.setCurrentContextSafe(true)).

If you emit to Kafka, no problem. If you consume from Kafka using @incoming no problem either. But yes, you can use the annotation every time if you are sure that your method (and subsequent methods) are not going to use the context concurrently.

@uPagge
Copy link

uPagge commented Sep 18, 2023

In my case, @SafeVertxContext didn't help. I read from the cafe and save it in the database.

@yrodiere yrodiere removed the area/persistence OBSOLETE, DO NOT USE label Aug 14, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants