views:

67

answers:

2

[My Setup: Java EE 6 application, with EJB3.1, CDI/Weld, JSF2 running on Glassfish 3.0.1]

I read some articles about the new @Asynchronous methods in EJB3.1, but none of them mentioned the dangers of asynchronous methods and what you really have to care about.

In my app i'm having an @Asynchronous E-Mail service, sending lots of mails. I'm calling this Service from a CDI/Weld Bean. During my tests, i often experienced ConcurrentModificationExceptions, but until now i don't really understand where and why it crashes sometimes.

Just to show how my Beans roughly look like, the important parts:

@Stateful @LocalBean
public class EmailEJB {
  //... Injections

  @Asynchronous
  public Future<Integer> sendEmails(User user, Message message) {
    // ... send mails
    return new AsyncResult<Integer>(1);
  }
}

In my CDI-Bean, i'm using this EJB like this (exposing progress to JSF2):

@Named @SessionScoped 
public class MessageManager {
  @EJB 
  public EmailEJB emailEJB;

  public FutureEJB<Integer> progress;

  public Integer getProgress() {
    if (progress == null) return 0;
    else {
      return progress.get();
    }
  }

  public String sendMessage() {
    (...)
    progress = emailEJB.sendEmails(user, message);
    (...)
  }
}

I just wanted to ask in general: am i doing something completely wrong here (Scopes, injections, using Future)? What do i have to care for when using @Asynchronous methods, to avoid ConcurrentModificationExceptions?

I'm injecting the Email as an EJB. Will it be better to make the whole EmailEJB Asynchronous and inject it with @Inject @Asynchronous? What would be the difference?

Any hints welcome!

A: 

My biggest failure was to use the Session Scope for my CDI bean. This allows only one instance of the asynchronous EJB at once - propably resulting in the ConcurrentModificationException (i think its at a point where i re-assign a Future value).

So @Asynchronous methods/classes seem to be an ideal candidate for the ConversationScope. Changed my CDI bean accordingly, no exceptions so far.

ifischer
+1  A: 

Your usage of the asynchronous method should have been fine, though I wonder if you really want it to be @Stateful. Sounds like state inside the @Stateful bean is being modified (or iterated over) in another thread when the @Asynchronous method is being invoked. This can happen if the @Stateful bean has say a List field and a reference to that list is passed outside of the @Stateful bean and used. If the caller thread and the async thread both used the list, it would be a very bad thing unless you change it to a concurrent list of some sort.

If you do have state in the @Stateful bean, you might be better off extracting it into a value object that has final (immutable) fields and passing it to an @Asynchronous @Singleton method -- possibly with @Lock(READ) if the async method doesn't update any state in the @Singleton.

David Blevins