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

Improper handling of application exceptions on asynchronous ejb invocations

    Details

    • Steps to Reproduce:
      Hide

      Create the following ejb:

      @Singleton
      public class AsyncBean {
       
      	@Asynchronous
      	public Future<Void> doSomeStuff() throws MyException {
      		throw new MyException();
      	}
      }
      

      Call ths bean and poll the result via isDone(). It will never return true.

      On wildfly 10, it would immidiatly return true.

      Show
      Create the following ejb: @Singleton public class AsyncBean {   @Asynchronous public Future<Void> doSomeStuff() throws MyException { throw new MyException(); } } Call ths bean and poll the result via isDone(). It will never return true. On wildfly 10, it would immidiatly return true.
    • Affects:
      Compatibility/Configuration
    • Estimated Difficulty:
      Low

      Description

      If an asynchronous invocation of an ejb method throws an application exception (declared exception) then the returned future will always return false on isDone(). That means: the client will never know that the operation has finished (unscuccessfully) unless get() is called which would rethrow the original exception.

      This behavior has changed from wildfly 10.1.0.Final to 11.0.0.Final.

      I pretty sure that the problem is in org.jboss.as.ejb3.component.interceptors.AsyncInvocationTask.

      The isDone Method is implemented like this:

          @Override
          public boolean isDone() {
              return status == ST_DONE;
          }
      

      But status can be one of:

          private static final int ST_RUNNING = 0;
          private static final int ST_DONE = 1;
          private static final int ST_CANCELLED = 2;
          private static final int ST_FAILED = 3;
      

      And and exception sets the status to

          private synchronized void setFailed(final Exception e) {
              this.failed = e;
              status = ST_FAILED;
              done();
          }
      

      So it's pretty obvious.

      The javadoc on java.util.concurrent.Future states:

      Completion may be due to normal termination, an exception, or cancellation – in all of these cases, this method will return true.

      So the isDone() method should look more like this:

          @Override
          public boolean isDone() {
              return status == ST_DONE || status == ST_FAILED || status == ST_CANCELLED;
          }
      

      In wildfly 10, there was a single boolean variable "done" which was set to true in all three cases:

      • cancel()
      • setResult(...) and
      • setFailed(...)

        Gliffy Diagrams

          Attachments

            Activity

              People

              • Assignee:
                Unassigned
                Reporter:
                andrejkolontai Andrej Kolontai
              • Votes:
                0 Vote for this issue
                Watchers:
                1 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved: