How to inject a CDI bean when using Jersey ManagedAsync

411 views
Skip to first unread message

Darren H

unread,
Jul 21, 2020, 6:35:13 AM7/21/20
to Payara Forum
Hi, 

I'm looking into payara micro performance and saw examples of how to use asynchronous processing for longer running API calls via Jersey...


This is great as implementing this for a longer lived call simulated using a Thread.sleep means that a single instance is processing thousands more requests a second. However the question is how to make use of this to call CDI beans. If I inject a request scoped bean into my jersey class then it works fine when doing synchronous processing, however as soon as I use the @ManagedAsync annotation then I get the following error when calling my request scoped bean:

org.jboss.weld.contexts.ContextNotActiveException: WELD-001303: No active contexts for scope type javax.enterprise.context.RequestScoped

I'm assuming that's because the thread call is now outside of the context created by the initial request into jersey, however this effectively renders asynchronous processing useless as I'm not able to use all the container features available to my CDI means. Is there something I should be doing to support this or is it simply not possible to use both together? 

Many thanks,
Darren 

Ondro Mihályi

unread,
Jul 21, 2020, 12:56:48 PM7/21/20
to Darren H, Payara Forum
Hi Darren,

The problem is that the Jersey annotation @ManagedAsync doesn't run the background task in a managed thread and then CDI doesn't work well.

You should do one of the following:
  • change the method to return CompletionStage instead of void. Then you would return an instance of CompletableFuture instead of calling asyncResponse.resume. The whole method would be executed in a background thread within a Request scope:
        @GET
        public CompletionStage asyncGet() {
            String result = service.veryExpensiveOperation();
            return CompletableFuture.completedFuture(result);
        }
  • use Executor manually, but remember that you need to inject a managed executor:

        @Resource
        private ManagedExecutorService mes;

        @GET
        public void asyncGet(@Suspended final AsyncResponse asyncResponse) {
                executor.execute(() -> {

  • Turn the JAX-RS resource into an EJB by adding @Stateless annotation to the class and use the Asynchronous annotation instead of @ManagedAsync:
@Stateless
public class Resource {

        @GET
        @Asynchronous
        public void asyncGet(@Suspended final AsyncResponse asyncResponse) {
            String result = service.veryExpensiveOperation();
            asyncResponse.resume(result);
        }
    }

ut 21. 7. 2020 o 12:35 'Darren H' via Payara Forum <payara...@googlegroups.com> napísal(a):
--
You received this message because you are subscribed to the Google Groups "Payara Forum" group.
To unsubscribe from this group and stop receiving emails from it, send an email to payara-forum...@googlegroups.com.
To view this discussion on the web, visit https://groups.google.com/d/msgid/payara-forum/ad127ed4-b239-4030-b5f5-0c03862db3c5o%40googlegroups.com.

Darren H

unread,
Jul 22, 2020, 5:14:56 AM7/22/20
to Payara Forum
Hi Ondro, 

That's awesome thanks for the response. I've tried the first two solutions and they work great. Is there a preferred method out of those, or pros / cons to using each of them? I guess turning my resource into an EJB would add extra overhead of it having to go from the web container to the EJB container? 

Many thanks,
Darren
To unsubscribe from this group and stop receiving emails from it, send an email to payara...@googlegroups.com.

Ondro Mihályi

unread,
Jul 27, 2020, 4:12:36 AM7/27/20
to Darren H, Payara Forum
There’s very little overhead with EJB and you'll get built in EJB monitoring in Payara for free. But I'm not sure that the original HTTP thread would be reused while waiting for the asynchronous operation, better test this. 

I recommend the first option if you prefer simple solution and don't care which executor runs your background task. The second option allows you to choose a specific executor if you want to run different tasks on different executors so that they can't steal each other's threads. 


Dňa st 22. 7. 2020, 11:14 'Darren H' via Payara Forum <payara...@googlegroups.com> napísal(a):
To unsubscribe from this group and stop receiving emails from it, send an email to payara-forum...@googlegroups.com.
To view this discussion on the web, visit https://groups.google.com/d/msgid/payara-forum/7cc76283-fc8d-497b-976c-dabf245549c2o%40googlegroups.com.
Reply all
Reply to author
Forward
0 new messages