Asynchronous Processing in JAX-RS 2.x

Quick introduction of asynchrnous processing in JAX-RS 2.x on both server-side and client-side.

Overview

In this article, I want to share with you how to use asynchronous processing in JAX-RS 2.x on both server-side and client-side. Asynchronous processing is a technique that enables a better and more efficient use of processing threads. On the client-side, a thread may be used for updating UI, it that thread is blocked waiting for a response, it may degrade the user experience. On the sever-side, a thread that is processing a request should avoid blocking while waiting for an external event to complete so that other requests arriving to the server can be processed.

After reading this article, you will understand:

  • How to process asynchronously on the server-side via AsyncResponse
  • How to process asynchronously on the server-side via CompletableStage
  • Compatibility with other JAX-RS annotations
  • How to process asynchronously on the client-side via Invocation#async
  • How to go further on this topic

Server API: AsyncResponse

The first choice of doing asynchronous processing in JAX-RS is to use AsyncResponse combined with annotation @Suspended. In this way, we inform the JAX-RS implementation that the response is not available upon return but will be produced in the future. This is done by first suspending the response and only resuming it once the asynchronous processing is done.

@Path("async")
public class MyAsyncResource {

  @GET
  @Path("longRunning1")
  public void longRunning1(@Suspended AsyncResponse response) {
    executor.submit(() -> {
        Thread.sleep(100);
        response.resume("Welcome to async world!");
        return null;
    });
  }

  ...
}

In the code snippet above, instead of producing a response immediately, it forks a (non-request) thread to execute a long-running operation and returns it immediately. The connection is only resumed when AsyncResponse#resume is called.

Server API: CompletableStage

The second choice of doing asynchronous processing in JAX-RS is to return an instance of CompletableStage, a new Java interface introduced in Java 8. Returning a completable stage indicates to JAX-RS implementation that the asynchronous processing is enabled.

@Path("async")
public class MyAsyncResource {

  @GET
  @Path("longRunning2")
  public CompletionStage<String> longRunning2() {
    CompletableFuture<String> future = new CompletableFuture<>();
    executor.submit(() -> {
        Thread.sleep(100);
        future.complete("Welcome to async world, again!");
        return null;
    });
    return future;
  }

  ...
}

In the code snippet above, instead of producing a response immediately, it forks a (non-request) thread to execute a long-running operation and returns it immediately. The connection is only resumed when the future is completed, i.e. when the method CompletableFuture#complete is called.

Compatibility With Other Annotations

Asynchronous processing is compatible with JAX-RS annotations. When using @Suspended, you can still use other JAX-RS annotations, such as @PathParam, @QueryParam:

@Path("async")
public class MyAsyncResource {

  @GET
  @Path("longRunning3/{id}")
  public void longRunning3(
      @PathParam("id") String id,
      @QueryParam("key") String value,
      @Suspended AsyncResponse response) {
    ...
  }
}

Client API

Now, let’s take a look on the client-side. The fluent API supports asynchronous invocations as part of the invocation building process. Method async can be used to set the invocation asynchronous:

WebTarget target = ClientBuilder.newClient().target(uri);
Future<String> future = target
    .path("async/longRunning1")
    .request()
    .async()
    .get(
        new InvocationCallback<String>() {
          @Override
          public void completed(String s) {
            // do something
          }

          @Override
          public void failed(Throwable throwable) {
            // process error
          }
        });

Going Further

How to go further from here?

Conclusion

In this article, we see how to use asynchronous processing in JAX-RS 2.x to enable a better and more efficient use of processing threads. On the server-side, we talked about @Suspeded AsyncResponse and CompletableStage; on the client-side, we talked about Invocation#async in the fluent API. Interested to know more? You can subscribe to the feed of my blog, follow me on Twitter or GitHub. Hope you enjoy this article, see you the next time!

References

  • Pavel Bucek and Santiago Pericas-Geertsen, “JAX-RS: JavaTM API for RESTful Web Services (version 2.1)”, Java Community Process (JCP), 2017. https://jcp.org/en/jsr/detail?id=370