question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Regression 2.x - Injecting reactive producer in an transactional bean loses the transaction

See original GitHub issue

Describe the bug

A regression bug was introduced with the 2.x release of Quarkus, when injecting an reactive producer in an transactional bean, the transaction gets lost.

A sample-application (based on the hibernate-orm-quickstart) has been created in a fork of the quickstarts.. The sample adds an EventPublisher for Kafka after persisting a new entity.

The bug appeared after upgrading to Quakrus 2.x

Expected behavior

Transaction finished successfully and sends event to Kafka.

Actual behavior

Exception occurs

ERROR [org.acm.hib.orm.FruitResource] (executor-thread-0) Failed to handle request: io.quarkus.arc.ArcUndeclaredThrowableException: Error invoking subclass method
        at org.acme.hibernate.orm.FruitResource_Subclass.create(FruitResource_Subclass.zig:518)
        at org.acme.hibernate.orm.FruitResource_ClientProxy.create(FruitResource_ClientProxy.zig:248)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:247)
        at io.quarkus.resteasy.runtime.standalone.RequestDispatcher.service(RequestDispatcher.java:73)
        at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.dispatch(VertxRequestHandler.java:138)
        at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler$1.run(VertxRequestHandler.java:93)
        at io.quarkus.vertx.core.runtime.VertxCoreRecorder$13.runWith(VertxCoreRecorder.java:503)
        at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2442)
        at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1476)
        at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
        at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.base/java.lang.Thread.run(Thread.java:831)
Caused by: javax.transaction.RollbackException: ARJUNA016053: Could not commit transaction.
        at com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionImple.commitAndDisassociate(TransactionImple.java:1307)
        at com.arjuna.ats.internal.jta.transaction.arjunacore.BaseTransaction.commit(BaseTransaction.java:128)
        at io.quarkus.narayana.jta.runtime.CDIDelegatingTransactionManager.commit(CDIDelegatingTransactionManager.java:102)
        at io.quarkus.narayana.jta.runtime.CDIDelegatingTransactionManager_Subclass.commit$$superforward1(CDIDelegatingTransactionManager_Subclass.zig:386)
        at io.quarkus.narayana.jta.runtime.CDIDelegatingTransactionManager_Subclass$$function$$6.apply(CDIDelegatingTransactionManager_Subclass$$function$$6.zig:24)
        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(InvocationInterceptor_Bean.zig:521)
        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 io.quarkus.narayana.jta.runtime.CDIDelegatingTransactionManager_Subclass.commit(CDIDelegatingTransactionManager_Subclass.zig:983)
        at io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorBase.endTransaction(TransactionalInterceptorBase.java:365)
        at io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorBase.invokeInOurTx(TransactionalInterceptorBase.java:165)
        at io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorBase.invokeInOurTx(TransactionalInterceptorBase.java:103)
        at io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorRequired.doIntercept(TransactionalInterceptorRequired.java:38)
        at io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorBase.intercept(TransactionalInterceptorBase.java:57)
        at io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorRequired.intercept(TransactionalInterceptorRequired.java:32)
        at io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorRequired_Bean.intercept(TransactionalInterceptorRequired_Bean.zig:340)
        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 org.acme.hibernate.orm.FruitResource_Subclass.create(FruitResource_Subclass.zig:496)
        ... 31 more
        Suppressed: javax.transaction.xa.XAException: Error trying to transactionCommit local transaction: Enlisted connection used without active transaction
                at io.agroal.narayana.LocalXAResource.xaException(LocalXAResource.java:140)
                at io.agroal.narayana.LocalXAResource.xaException(LocalXAResource.java:134)
                at io.agroal.narayana.LocalXAResource.commit(LocalXAResource.java:72)
                at com.arjuna.ats.internal.jta.resources.arjunacore.XAResourceRecord.topLevelOnePhaseCommit(XAResourceRecord.java:702)
                at com.arjuna.ats.arjuna.coordinator.BasicAction.onePhaseCommit(BasicAction.java:2400)
                at com.arjuna.ats.arjuna.coordinator.BasicAction.End(BasicAction.java:1502)
                at com.arjuna.ats.arjuna.coordinator.TwoPhaseCoordinator.end(TwoPhaseCoordinator.java:96)
                at com.arjuna.ats.arjuna.AtomicAction.commit(AtomicAction.java:162)
                at com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionImple.commitAndDisassociate(TransactionImple.java:1295)
                ... 54 more
        Caused by: java.sql.SQLException: Enlisted connection used without active transaction
                at io.agroal.pool.ConnectionHandler.verifyEnlistment(ConnectionHandler.java:362)
                at io.agroal.pool.ConnectionHandler.transactionCommit(ConnectionHandler.java:331)
                at io.agroal.narayana.LocalXAResource.commit(LocalXAResource.java:69)
                ... 60 more

How to Reproduce?

Steps to reproduce.

Checkout Commit https://github.com/lostiniceland/quarkus-quickstarts/commit/f9300b1effa8fc61fe1a14ccfba343761619862a go to hibernate-orm-quickstarts

docker-compose up
./mvnw quarkus:dev
curl -X 'POST' \
  'http://localhost:8080/fruits' \
  -H 'accept: */*' \
  -H 'Content-Type: application/json' \
  -d '{
  "name": "foo"
}'

Check Log

Output of uname -a or ver

No response

Output of java -version

16

GraalVM version (if different from Java)

No response

Quarkus version or git rev

2.1.0.Final, 2.0.3.Final

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

Maven 3.8.1

Additional information

Changing the version (runtime and plugin) to 1.13.7, no error occurs.

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:10 (8 by maintainers)

github_iconTop GitHub Comments

2reactions
lostinicelandcommented, Aug 17, 2021

I do not agree that the issue is solved with the remarks done in #18450 First, there is an SQLException thrown at the end of the exception (not a Kafka-Exception), which doesnt show up when using Quarkus 1.3.x. So there is something wrong with 2.x Sure, the example is plain wrong in general for non-reactive api, because Kafka does not take part in a JTA transaction, so you should not do this dual-write. You might end up with a written Kafka-Message and a failed transaction afterwards due to a db constraint for instance because JTA finishes when the transactional-method is exited. Wrapping non-JTA in a Future and blocking will not solve this issue. Or is the exception an improvement over 1.3.x, meaning that it protects from something that shouldnt be done (what 1.3.x did not cover)

0reactions
ozangunalpcommented, Aug 17, 2021

I find that in general, using reactive messaging streams in integration with other reactive APIs is not that obvious. We need a place to document these “common integration patterns”. Here’s a couple that comes to my mind :

  • Persisting Kafka messages with hibernate-reactive,
  • Writing messages to Kafka in hibernate transactions,
  • Exposing Kafka topics using server-side events and resteasy-reactive,
  • Writing to Kafka topics using HTTP endpoint,

I used Kafka as an example but it goes for all reactive messaging connectors.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Reactive Transactions with Spring
At the time our journey began, we had no reactive form of transactional integrations, so this question was simple to answer: There's no...
Read more >
SpyBean and @Transactional and SelfInjection regression in ...
Hi, when using @SpyBean on a transactional (proxied) bean that uses self injection (to have transaction semantics for inner calls), ...
Read more >
Spring reactive transaction gets committed on cancel ...
My project uses spring-data-mongodb , everything is reactive. There is a bean with a transactional method using declarative transactions.
Read more >
Hazelcast IMDG Release Notes
Fixed a regression issue where the locked and expired entry keys ... The eviction of the idle entries is now stable in IMDG...
Read more >
07: Debugging Spring Transaction Management
Never just trust that adding @Transactional annotation is going to create a transactional boundary for your service layer.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found