Hot questions for Using Enterprise JavaBeans in asynchronous

Question:

I am injecting a @Stateless bean in a Asynchronous Servlet and calling @Asynchronous method from the Serrvlet. In the server logs of the jboss i am not able to see any of the Exception but whhile starting the Java Mission Control ,Flight Recorder i can see ContextNotActiveExcetion whenever Servlet makes a call to the @Asyncrhonous method.

Servlet ::

@WebServlet(urlPatterns = { "/asyncservice" }, asyncSupported = true)
public class AsyncServiceServlet extends HttpServlet {

@Inject
private Service service;

protected void doPost(final HttpServletRequest request, final HttpServletResponse response)
        throws ServletException, IOException {
    final AsyncContext asyncContext = request.startAsync(request, response);
    asyncContext.start(new Runnable() {
        @Override
        public void run() {
            try {
                service.service(asyncContext);
            } catch (ContextNotActiveException | IOException e) {
                e.printStackTrace();
            }
        });
    }

Service class ::

@Stateless
public class Service {

@Asynchronous
public void service(final AsyncContext asyncContext) throws IOException {
    HttpServletResponse res = (HttpServletResponse) asyncContext.getResponse();
    res.setStatus(200);
    asyncContext.complete();
     }
}

the stack trace i can see in the flight Recorder ::

      java.lang.Throwable.<init>()  4
      java.lang.Exception.<init>()  4
      java.lang.RuntimeException.<init>()   4
      javax.enterprise.context.ContextException.<init>()    4
      javax.enterprise.context.ContextNotActiveException.<init>()   4
      org.jboss.weld.context.ContextNotActiveException.<init>(Enum,Object[])    4
      org.jboss.weld.manager.BeanManagerImpl.getContext(Class)  4
      org.jboss.as.weld.ejb.EjbRequestScopeActivationInterceptor.processInvocation(InterceptorContext)  4
     org.jboss.invocation.InterceptorContext.proceed()  4
        org.jboss.invocation.InitialInterceptor.processInvocation(InterceptorContext)   4
   org.jboss.invocation.InterceptorContext.proceed()    4
     org.jboss.invocation.ChainedInterceptor.processInvocation(InterceptorContext)  4
 org.jboss.as.ee.component.interceptors.ComponentDispatcherInterceptor.processInvocation(InterceptorContext)    4
    org.jboss.invocation.InterceptorContext.proceed()   4
      org.jboss.as.ejb3.component.pool.PooledInstanceInterceptor.processInvocation(InterceptorContext)  4
  org.jboss.invocation.InterceptorContext.proceed() 4
    org.jboss.as.ejb3.tx.CMTTxInterceptor.invokeInOurTx(InterceptorContext,TransactionManager,EJBComponent) 4
    org.jboss.as.ejb3.tx.CMTTxInterceptor.required(InterceptorContext,EJBComponent,int) 4
  org.jboss.as.ejb3.tx.CMTTxInterceptor.processInvocation(InterceptorContext)

I have been going through many posts but still the issue remain the same, please help me out .


Answer:

javadoc for AsyncContext.start:

Registers the given AsyncListener with the most recent asynchronous cycle that was started by a call to one of the ServletRequest.startAsync() methods. The given AsyncListener will receive an AsyncEvent when the asynchronous cycle completes successfully, times out, or results in an error.

Implying that by the time this call to

service.service(asyncContext);

Is made, the httpservletrequest "context" may not be available and the request may even have been committed, resulting to CDI not being able to determine any '@RequestScoped' beans used by your service.

Note that AsyncContext.start registers an onEvent to be invoked when the async call is completed, or on error, not when it starts.

You would probably want to add listeners to be invoked before calling AsyncContext.start

Question:

I have two tasks that I need to perform say task1 and task2 which are a part of same business process. I have to give response to the end user when task1 completes so it's response time have to be minimized.

My current approach is to perform task1 and as soon as task1 is finished, invoke task2 method asynchronously. task2 is complicated and it's response time is out of my control as it has some external dependency.

@Stateless
public class SessionBean1 {

    @Inject
    SessionBean2 sessionBean2;

    public void doTask1(){
        // task one stuff
        sessionBean2.doTask2();
    }

}



@Stateless
public class SessionBean2 {

    @Asynchronous
    public void doTask2(){
        // do task2 stuff
    }

}

In websphere 8.0 (the EJB container in use) synchronous methods and asynchronous methods are run by different thread pools.

My initial assumption was that even if task2 is performing badly, task1 would have no impact, but sadly that's not true.

If task2 is performing badly, all threads from asynchronous thread pool will be occupied. This will cause task1 to wait for asynchronous threads to be free and hence task1 has impact.

The message in websphrere server logs : The request buffer for thread pool WorkManager.WebSphere_EJB_Container_AsynchMethods_Internal_WorkManager has reached its capacity

My question is what would be a proper way to achieve what I'm trying to achieve here.


Answer:

Another alternative would be to increase the "Work request queue size" of the "EJB asynchronous method invocation settings" in the Admin Console. This is a queue, before the actual thread pool itself, so this might buy you some more time.

Ideally this should be used in combination with the timeouts suggested above.

Question:

We have two EJB session beans as given below;

@Stateless
public class MyStatelessSessionBean{
      @EJB
       MyStatefulSessionBean statefulBean;
      public void methodA(){
          statefulBea.methodB();
      }
}

@Stateful
@ TransactionAttribute(TransactionAttributeType.REQUIRED)
public class MyStatefulSessionBean {
     @Asynchronous
     public void methodB(){
     }

}

A client, which is not in any in any transaction, invoke methodA of MyStatelessSessionBean. How many distict transactions will be started by container after all processing has completed ?


Answer:

There will be 2 transactions started. As EJB 3.1 specification states in point 4.5.3:

Client transaction context does not propagate with an asynchronous method invocation. From the Bean Developer’s view, there is never a transaction context flowing in from the client. This means, for example, that the semantics of the REQUIRED transaction attribute on an asynchronous method are exactly the same as REQUIRES_NEW.

Question:


Answer:

Basically, the answer can be found in the EJB 3.1 specification:

The enterprise bean must not attempt to manage threads. The enterprise bean must not attempt to start, stop, suspend, or resume a thread, or to change a thread’s priority or name. The enterprise bean must not attempt to manage thread groups. These functions are reserved for the EJB container. Allowing the enterprise bean to manage threads would decrease the container’s ability to properly manage the runtime environment.

I guess the explanation speaks for itself. Java EE is typically implemented in a container on an application server, and the specification has been designed to give the container the best conditions to effeciently do its job.

Another reason I can think of, and I guess one of the reasons the Java EE specification exists at all, is that it allows for reusability. There is no need to reinvent the wheel, so to speak.

Question:

I develop an application that at some point starts to aggregate an infomation from a bunch of services. Some of that services are called via SOAP interfaces synchronously and some of them works asynchronosly - I have to send a request to JMS queue Q1 and get an answer to Q2 at some point.

The problem is that the app sends requests in one thread and the responses a processed using MDBs (Message-Driven Bean). The solution from the top of my head is to store already aggregated responses in some shared container (like ConcurrentHashMap) with some correlationId. So when an MDB gets a response it looks through the shared container and adds response to the corresponding record.

The app runs on WildFly AS in domain HA mode.

  1. Are there some problems that I can run into with this approach? Like the container will be instantiated one for each node in cluster.
  2. Or I can accidently process so many requests that I will store so many responses that I will get OutOfMemoryError?
  3. What are the best approaches for this kind of problems?

Answer:

Let me answer your questions:

  1. A response to a JMS service call could arrive anytime (quite soon : the destination server down, the operator take a rest, etc). So you should store the requests in a database during the data aggregation.
  2. Performance issues always could happen when you serve many requests parallel. And if you have asynchronous answers you can store many-many hashes for a long time (or with SFSB activate/passivate) till the last answer arrives. The first answer (partly) solve this problem as well, because it stores most of the data in the db and takes just the current ones in the memory. And more robust. The persistent data live survive a server crash/shutdown.
  3. When you need the data, create a db entry for all and send out the requests with its PK in the header. When an answer arrives, its header contains the same PK for the identification. The MDBs are best way to receive them. But use them just to receive the messages. Process its contents by EJBs. Delegate the message contents synchronously to the EJB(s) and acknowledge them according to the EJB answers. At the very end of the EJB processing fetch the IDs of the unprocessed requests belong to the current aggregation. If there is no one, (remove the query entries from the db table and) call the appropriate EJB (via MDB?) to proceed the work with the fulfilled data needs.