Reputation: 4636
Before adding CDI into our application I had created a resource that used the @Suspended AsyncResponse
object to implement long polling for a chat client. What I did was create a new newSingleThreadExecutor()
and submit
a Runnable
to it that used .wait(30000)
on a message list until notification that a new message was sent. Inside that task I used the HttpServletRequest
which was obtained using @Context
and everything worked perfectly.
However once we added CDI to our application and even without making the resource class a bean (scanning only annotated beans and we didn't give it any scope annotation) I got a runtime exception that the request object INSIDE the Runnable
task couldn't be accessed because of an illegal state exception:
Method threw 'java.lang.IllegalStateException' exception. Cannot evaluate com.sun.proxy.$Proxy74.toString()
I'm not really sure why this happens but I know it is CDI related since it refers to a proxy object. One guess is that the resource class itself has become CDI scoped and that scope can't be accessed from a different thread? I read somewhere that manually started threads are not managed and thus can't have access to any scope related objects. However how did this use to work until CDI was implemented?
Right now I THINK I've solved the issue (that is releasing the thread servicing request I/O and having a worker take over the waiting until notified) using jersey's @ManagedAsync
annotation which supposedly has the whole method be run in an internal jersey executor service. Is this correct? Also in that case, is there any need of the AsyncResponse
object?
EDIT: I have NOT solved the issue. @ManagedAsync
worked when the resource class was not defined as a CDI bean. After making it @RequestScoped
, whenever I try to call the method I get the following exception
org.jboss.weld.context.ContextNotActiveException: WELD-001303: No active contexts for scope type javax.enterprise.context.RequestScoped
I think this is because the request can end before the async thread has finished which means all scope objects (like HttpServletRequest) will be destroyed and thus we won't have access to them. Is there a way to used @ManagedAsync
in a @RequestScoped
bean and make use of @Context HttpServletRequest
??
TL;DR:
@ManagedAsync
in a @RequestScoped
cdi bean?Old method:
@GET
@Path("method")
public void method(@Context HttpServletRequest request, @Suspended AsyncResponse ar) {
//request object was accessible here
Executors.newSingleTHreadExecutor().submit(() -> {
//request object was also accessible here but lost access after implementing CDI.
Object o = foo.bar(request);
ar.resume(Response.ok(o).build());
});
}
Current non-working method:
@GET
@Path("method")
@ManagedAsync
public void method(@Context HttpServletRequest request, @Suspended AsyncResponse ar) {
Object o = foo.bar(request);
ar.resume(Response.ok(o).build()); //Is there any point to this?
}
Upvotes: 1
Views: 2001
Reputation: 11723
To answer your question - no. You cannot use async and request scoped objects. Async support is lacking in CDI - see also https://issues.jboss.org/browse/CDI-452
Upvotes: 2