Call Methods Asynchronous in EJB

Hasan Tuncay picture Hasan Tuncay · May 28, 2013 · Viewed 14k times · Source

I try to save the result of a login process for statistics to the database asynchronously to save time during the login method. But somehow the login process takes longer if i add a thread.sleep to the async method. Why is that? I thought the authenticate method will not wait for the writeResultToStats methode to finish.

    @Stateless
    @LocalBean
    @ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
    @TransactionManagement(TransactionManagementType.CONTAINER)
    public class CustomerBeanTest {

        @PersistenceContext(unitName = WebPersistenceUnits.QISADS)
        private EntityManager em_local;

        @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
        public void authenticate(Long loginid, String cmppassword) {
            try {
                Login l = em_local.find(Login.class, loginid);
                String s = l.getPassword();
                if (!s.equalsIgnoreCase(cmppassword))
                    throw new PasswordMissmatchException();
                writeResultToStats(loginid, true);
            } catch (PasswordMissmatchException e) {
                writeResultToStats(loginid, false);
            }
        }

        @Asynchronous
        @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
        private void writeResultToStats(Long loginID, boolean success) {

            try { // just for testing
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            LogUtils log = new LogUtils(this);
            Login l = em_local.find(Login.class, loginID);
            if (success) {
                l.setSuccessLast(new Date());
                l.setSuccessCount(l.getSuccessCount()+1);
                log.log(Level.INFO, "Update Login Stat Success [%d, %s, %d]", l.getId(), l.getName(), Thread.currentThread().getId());
            } else {
                l.setFailureLast(new Date());
                l.setFailureCount(l.getFailureCount()+1);
                log.log(Level.INFO, "Update Login Stat Fail [%d, %s, %d]", l.getId(), l.getName(), Thread.currentThread().getId());
            }

        }

    }

Answer

Aksel Willgert picture Aksel Willgert · May 28, 2013

Try to break out the asynchronous method into a separate ejb. Methods invoked from inside the same ejb will be handled just like local method-invocations. The container is not capable of intercept the method call.

EJB-Annotations is only in play when invocation is done by the container.

Alternative

You can have the method in the same EJB but make sure you use the EJB Local interface to lookup the bean and access the methord.