Search code examples
javaasynchronousejbjava-ee-8payara-micro

Payara @Asynchronous not asynchronous


I'm working on a project powered by Payara Micro and it is configured by a domain.xml file.

I'm facing an issue with the @Asynchronous annotation.

While the Oracle documentation explains this:

Clients calling asynchronous methods, however, immediately have control returned to them by the enterprise bean container.

https://docs.oracle.com/javaee/7/tutorial/ejb-async001.htm

My @Asynchronous annotated method does not return immediately.

@Path("foo")
public class FooResource {
  @GET
  public String get() {
    System.out.println("Request started");
    this.doSomething();
    System.out.println("Request ended");
    return "Hello world! ";
  }

  @Asynchronous
  public void doSomething() {
    try {
      System.out.println("Long task started");
      Thread.sleep(2000);
      System.out.println("Long task ended");
    } catch (InterruptedException e) {
      System.out.println("Long task failed");
    }
  }
}

In my mind it should result in:

Request started
Long task started
Request ended
Long task ended

but it results in:

Request started
Long task started
Long task ended
Request ended

I published on Github a simple Gradle project to reproduce the behavior here.


Solution

  • Your method invocation will be truly asynchronous if you actually invoke the method of an EJB. The call in your sample is a local method call, completely bypassing the container and its annotation processing.

    A proper EJB invocation would require an actual EJB:

    @Stateless
    class MyEJB {
    
      @Asynchronous
      public void doSomething() {
        try {
          System.out.println("Long task started");
          Thread.sleep(2000);
          System.out.println("Long task ended");
        } catch (InterruptedException e) {
          System.out.println("Long task failed");
        }
      }
    }
    

    ... and the method invocation in your resource class:

    class MyResource {
    
    @Inject MyEJB myEJB;
    
    @Path("foo")
    public class FooResource {
      @GET
      public String get() {
        System.out.println("Request started");
        myEJB.doSomething(); // <-- This is the important change!
        System.out.println("Request ended");
        return "Hello world! ";
      }
    }