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

MessageDrivenComponent startDelivery/stopDelivery is not thread safe

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Done
    • Icon: Major Major
    • 10.0.0.CR5
    • 10.0.0.CR4
    • EJB, JMS
    • None
    • Hide

      1) Take the helloworld-mdb quickstart, and add @ClusteredSingleton (from jboss-ejb3-exi-api) to a MDB.
      2) Add a breakpoint on MessageDrivenBean.activate()
      3) Deploy and start the server

      Either one or two threads may hit the breakpoint concurrently, depending on whether the first runs "this.deliveryActive = true" before the second does the check:
      org.jboss.as.ejb3.component.messagedriven.MessageDrivenComponent.activate() line: 238
      org.jboss.as.ejb3.component.messagedriven.MessageDrivenComponent.startDelivery() line: 265
      org.jboss.as.ejb3.component.messagedriven.MdbDeliveryControllerService.start(org.jboss.msc.service.StartContext) line: 51
      org.jboss.msc.service.ServiceControllerImpl$StartTask.startService(org.jboss.msc.service.Service<? extends S>, org.jboss.msc.service.StartContext) line: 1948
      org.jboss.msc.service.ServiceControllerImpl$StartTask.run() line: 1881
      org.jboss.msc.service.ServiceContainerImpl$ContainerExecutor(java.util.concurrent.ThreadPoolExecutor).runWorker(java.util.concurrent.ThreadPoolExecutor$Worker) line: 1142
      java.util.concurrent.ThreadPoolExecutor$Worker.run() line: 617
      org.jboss.msc.service.ServiceContainerImpl$ServiceThread(java.lang.Thread).run() line: 745

      org.jboss.as.ejb3.component.messagedriven.MessageDrivenComponent.activate() line: 238
      org.jboss.as.ejb3.component.messagedriven.MessageDrivenComponent.start() line: 214
      org.jboss.as.ee.component.ComponentStartService$1.run() line: 54
      java.util.concurrent.Executors$RunnableAdapter<T>.call() line: 511
      java.util.concurrent.FutureTask<V>.run() line: 266
      java.util.concurrent.ThreadPoolExecutor.runWorker(java.util.concurrent.ThreadPoolExecutor$Worker) line: 1142
      java.util.concurrent.ThreadPoolExecutor$Worker.run() line: 617
      org.jboss.threads.JBossThread(java.lang.Thread).run() line: 745
      org.jboss.threads.JBossThread.run() line: 320

      Show
      1) Take the helloworld-mdb quickstart, and add @ClusteredSingleton (from jboss-ejb3-exi-api) to a MDB. 2) Add a breakpoint on MessageDrivenBean.activate() 3) Deploy and start the server Either one or two threads may hit the breakpoint concurrently, depending on whether the first runs "this.deliveryActive = true" before the second does the check: org.jboss.as.ejb3.component.messagedriven.MessageDrivenComponent.activate() line: 238 org.jboss.as.ejb3.component.messagedriven.MessageDrivenComponent.startDelivery() line: 265 org.jboss.as.ejb3.component.messagedriven.MdbDeliveryControllerService.start(org.jboss.msc.service.StartContext) line: 51 org.jboss.msc.service.ServiceControllerImpl$StartTask.startService(org.jboss.msc.service.Service<? extends S>, org.jboss.msc.service.StartContext) line: 1948 org.jboss.msc.service.ServiceControllerImpl$StartTask.run() line: 1881 org.jboss.msc.service.ServiceContainerImpl$ContainerExecutor(java.util.concurrent.ThreadPoolExecutor).runWorker(java.util.concurrent.ThreadPoolExecutor$Worker) line: 1142 java.util.concurrent.ThreadPoolExecutor$Worker.run() line: 617 org.jboss.msc.service.ServiceContainerImpl$ServiceThread(java.lang.Thread).run() line: 745 org.jboss.as.ejb3.component.messagedriven.MessageDrivenComponent.activate() line: 238 org.jboss.as.ejb3.component.messagedriven.MessageDrivenComponent.start() line: 214 org.jboss.as.ee.component.ComponentStartService$1.run() line: 54 java.util.concurrent.Executors$RunnableAdapter<T>.call() line: 511 java.util.concurrent.FutureTask<V>.run() line: 266 java.util.concurrent.ThreadPoolExecutor.runWorker(java.util.concurrent.ThreadPoolExecutor$Worker) line: 1142 java.util.concurrent.ThreadPoolExecutor$Worker.run() line: 617 org.jboss.threads.JBossThread(java.lang.Thread).run() line: 745 org.jboss.threads.JBossThread.run() line: 320

      WFLY-4470 made a change to prevent MDBs being activated or deactivated multiple times, but it is not thread safe. A volatile boolean is used for the flag, but there is no protection against multiple threads invoking the methods simultaneously.

      Possible effects include:

      • activating the endpoint twice, with (probably) only one deactivation later, leading to not de-registering XA resources from the recovery manager properly
      • activate() and deactivate() running in the wrong order if done by separate threads

      Several simple solutions probably will not work correctly. Using an AtomicBoolean would stop multiple activations/deactivations from concurrent calls, but would mean that startDelivery() could return before the activation was one. Using a synchronized block or other exclusive lock would work, however since it involves invoking non-container code (the resource adapter), there could potentially be a deadlock risk if that invoked some related container functionality.

              jmesnil1@redhat.com Jeff Mesnil
              rhn-support-jlivings James Livingston (Inactive)
              Votes:
              0 Vote for this issue
              Watchers:
              8 Start watching this issue

                Created:
                Updated:
                Resolved: