[
https://issues.jboss.org/browse/WFLY-9529?page=com.atlassian.jira.plugin....
]
Scott Van Wart commented on WFLY-9529:
--------------------------------------
I just had a javax.naming.NameNotFoundException:
java:comp/TransactionSynchronizationRegistry with no immediate CDI events involved.
[~emmartins] I'm speculating that an earlier CDI event lead to a pollution of a
managed thread and that random chance lead this random thread to be used with a JMSContext
that was injected:
# Service.initialize( @Observes @Initialized( ApplicationScoped.class ) Object event )
gets called
# Call ManagedExecutorService.submit( Runnable ) from that thread.
# That Runnable executes and eventually submits another Runnable to the same executor
service.
# That Runnable is executed and itself submits a THIRD runnable to a completely separate
executor service.
# When this third runnable is run, it hits its first @Transactional barrier, then tries to
call JMSContext.createTextMessage which throws javax.naming.NameNotFoundException:
java:comp/TransactionSynchronizationRegistry.
This is an actual workflow in our application. A connection thread created in (2) submits
worker tasks (3) to process incoming events. The event discovers it needs to wait on
something else and registers a callback. When that something else happens the callback is
scheduled on the executor service (4).
What's immensely frustrating about this is things will run fine for several weeks or
possibly a month or more. Then I'll get a report back and immediately notice
"javax.naming.NameNotFoundException:
java:comp/TransactionSynchronizationRegistry" and play a game of musical chairs with
my uncomfortably obtuse list of workarounds until I find one that will keep things going
awhile longer.
Workarounds I have:
* Create a connection manually from java:/ConnectionFactory and manage its state from
start to finish. Any time I want it to participate in a distributed transaction I need to
look up java:comp/TransactionSynchronizationRegistry myself and register a
Synchronization. I can't take advantage of connection pooling and it really strains
the idea that it's a fully distributed transaction and not a risky post-commit hack. I
also can't use multithreading because a single JMS session created in this fashion
can't be used by multiple threads (if I'm interested in using transactions, which
I unquestionably am). In cases where I can't avoid multithreading, I'm queuing up
the data I want to send within the transaction, and only using the session at the very end
of the transaction to fire off its messages as quickly as possible. This kills
performance. I could pool connections, but then I might as well write my own
JMS<->container integration.
* Wrap all my JMSContext usage with a simple EJB. This absolutely kills performance on
anything but the occasional message.
* Don't use @Observes @Initialized( ApplicationScoped.class ). That would eliminate
only a small fraction of the CDI events we're using in our product.
Using injected JMS in a background task/thread leads to
NameNotFoundException: java:comp/TransactionSynchronizationRegistry
---------------------------------------------------------------------------------------------------------------------------
Key: WFLY-9529
URL:
https://issues.jboss.org/browse/WFLY-9529
Project: WildFly
Issue Type: Bug
Components: JMS, Naming
Affects Versions: 10.1.0.Final, 11.0.0.Final, 12.0.0.Final
Environment: Running on Windows 10, Java 64-bit 1.8.0_131
Reporter: Scott Van Wart
Assignee: Eduardo Martins
Labels: ActiveMQ, jms, transaction
Attachments: injected-jms.zip, injected-jms2.zip, wildfly-11-injected-jms.txt
If I try to use an @Injected JMSContext while executing within a background task
(ManagedExecutorService) or thread (ManagedThreadFactory), I get the attached stacktrace.
I've experienced this a number of times with Wildfly 10.1.0, including messages sent
in Infinispan's expiry task thread.
My original workaround was to submit an additional task on a separate thread to send the
message, then wait for it to complete. That seemed unreliable (sometimes it would still
produce NameNotFoundException). I've resorted to creating my own JMSContext by using
@Resource( lookup="java:/ConnectionFactory" ) and sending messages that way.
Both workarounds prevent the message sending logic from participating in any ongoing
transactions.
I'm also attaching a sample EAR project. It can be built with Maven. It creates a
background task that waits 3 seconds and then tries to send a JMS message in a new
transaction using an injected JMS context. I use the standalone-full.xml profile to run
it.
--
This message was sent by Atlassian JIRA
(v7.5.0#75005)