Uploaded image for project: 'WildFly'
  1. WildFly
  2. WFLY-3338

@Inject'ed JMSContext is not thread-safe

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Closed (View Workflow)
    • Priority: Major
    • Resolution: Done
    • Affects Version/s: 8.0.0.Final
    • Fix Version/s: 9.0.0.Alpha1
    • Component/s: JMS
    • Labels:
      None

      Description

      Section 12.4.4 of the JMS 2.0 spec says:

      If a method is called on an injected JMSContext when there is a JTA
      transaction (either bean-managed or container-managed), the scope of
      the JMSContext will be @TransactionScoped.

      This is not currently true in WildFly. As a test case, suppose you have the following two beans:

      import javax.annotation.Resource;
      import javax.enterprise.context.ApplicationScoped;
      import javax.enterprise.inject.Instance;
      import javax.inject.Inject;
      import javax.jms.JMSContext;
      import javax.jms.Topic;
      import javax.transaction.Transactional;
      
      @ApplicationScoped
      @Transactional
      public class AppScopedBean {
      	
      	@Inject
      	private JMSContext jmsCtx;
      	//private Instance<JMSContext> jmsCtx;
      	@Resource(lookup = "jms/topic/test")
      	private Topic topic;
      	
      	public void sendMessage() {
      		jmsCtx.createProducer().setDisableMessageID(true).setDisableMessageTimestamp(true).send(topic, "a message");
      		//jmsCtx.get().createProducer().setDisableMessageID(true).setDisableMessageTimestamp(true).send(topic, "a message");
      	}
      
      }
      
      import javax.annotation.Resource;
      import javax.enterprise.concurrent.ManagedThreadFactory;
      import javax.enterprise.context.ApplicationScoped;
      import javax.enterprise.context.Dependent;
      import javax.enterprise.context.Initialized;
      import javax.enterprise.event.Observes;
      import javax.inject.Inject;
      
      @Dependent
      public class ThreadLauncher {
      
      	@Resource
      	private ManagedThreadFactory threadFactory;
      	@Inject
      	private AppScopedBean bean;
      	
      	void start(@Observes @Initialized(ApplicationScoped.class) Object event) {
      		System.out.println("starting threads");
      		for (int i = 0; i < 5; i++) {
      			threadFactory.newThread(new SendRunnable()).start();
      		}
      		System.out.println("start finished");
      	}
      	
      	private class SendRunnable implements Runnable {
      
      		public void run() {
      			System.out.println("starting to send");
      			for (int i = 0; i < 100; i++) {
      				bean.sendMessage();
      			}
      			System.out.println("done sending");
      		}
      		
      	}
      	
      }
      

      If you deploy and run the above code, you will see a lot of this:

      2014-05-12 16:46:02,936 WARN [org.hornetq.core.client] (EE-ManagedThreadFactory-default-Thread-4) HQ212051: Invalid concurrent session usage. Sessions are not supposed to be used by more than one thread concurrently.: java.lang.Exception: trace

      That should not be happening if the JMSContext is really @TransactionScoped. The problem appears to be in org.jboss.as.messaging.deployment.JMSContextProducer, specifically the JMSContextWrapper.getDelegate() method. If two threads call it at the same time, the first will create a delegate but the second will receive the same delegate as the first, because the delegate doesn't get nulled until the transaction in the first thread completes.

      This means that both threads are using the same session at the same time, which is not allowed. I don't know how HornetQ detects concurrent use, but depending on how that works, it's also possible that messages will end up being part of the wrong transaction.

      A workaround is to inject Instance<JMSContext> instead of JMSContext directly (the two commented out lines of code). Since the JMSContext producer is @Dependent, each Instance.get() call will return a new instance, and only one thread will ever use any given instance.

        Attachments

          Activity

            People

            Assignee:
            jmesnil Jeff Mesnil
            Reporter:
            rcd Richard DiCroce
            Votes:
            2 Vote for this issue
            Watchers:
            5 Start watching this issue

              Dates

              Created:
              Updated:
              Resolved: