Search code examples
javaasynchronousjax-rsjava-ee-7

Should we always use Asynchronous JAX-RS resources For mobile backend?


I am building Mobile backend API using Java EE - JAX-RS 2.0 technology.

Since most of mobile client consumes are asynchronous http calls

so my question is: Should I use asynchronous feature for all JAX-RS resources? And the reason if not?

The below is the template Mobile Async API

@Path("/async_api")
public class AsyncResource {

    @GET
    @Path("/loadUsers")
    @Produces(MediaType.APPLICATION_JSON)
    public void loadUsers(@Suspended AsyncResponse asyncResponse) {

        //TODO: ManagedExecutorService

        new Thread(new Runnable() {

            @Override
            public void run() {
                List users = loadBigUsers();
                asyncResponse.resume(users);
            }

            private List loadBigUsers() {
                return null; // Return big list
            }

        }).start();
    }
}

Thank you!


Solution

  • In JAX-RS the @Suspendannotation and AsyncResponse are needed only in certain typical scenarios. The first scenario was already identified in your code example. It is long running tasks. In this case the AsyncResponse can be used to execute long running code in a background thread. While this would not make sense at the first glance we need to think about how an application server / container handles its requests. Usually there is a pool of threads that accepts and handles client requests. If you implement expensive operations inline in your JAX-RS service methods one of the threads in the pool is blocked for the entire runtime. With the AsyncResponse the executor thread gets returned to the pool and other requests can be served in parallel.

    @Path("/users")
    public class UserRestService {
    
        @GET
        public void getAllUsers(@Suspend final AsyncResponse asyncResponse) {
            new Thread(new Runnable(
                @Override
                public void run() {
                    List<Users> users = UserDAO.loadAllUsers();
                    asyncResponse.resume(users);
                }
            ) {}).start();
        }
    }
    

    The second application scenario for AsyncResponse is the often seen pattern of producer consumer patterns. Assuming you have a queue bound to the URL https://yourservice.at/queue/next then a @GET method can be used for a blocking take() on lets say a LinkedBlockingQueue. On the same URL you could bind a @POST method which adds data to the queue. In this case you would wrap up the functionality with the take() operation in an AsyncResponse.

    @Path("/queue/next")
    public class MessageQueueService {
    
        private static final LinkedBlockingQueue<AsyncResponse> suspendedResponses = new LinkedBlockingQueue<AsyncResponse>();
    
        @GET
        public void getNextMessage(@Suspend final AsyncResponse asyncResponse) {
            MessageQueueService.suspendedResponses.put(asyncResponse);
        }
    
        @POST
        public void putNewMessage(final String message) throws InterruptedException {
            AsyncResponse asyncResponse = suspendedResponses.take(); // note how this could also block a thread
            asyncResponse.resume(message);
        }
    }
    

    From these explanations you can also see, that the JAX-RS @Suspended mechanism is used to create an asynchronous server side task. Whether or not the same request is also executed in an asynchronous manner on the client is a whole different story.