Handling time outs in Async requests in JAX-RS
JAX-RS 2.0 provides support for asynchronous programming paradigm, both on client as well as on the server end. This post which highlights the time out feature while executing asynchronous REST requests on server side using the JAX-RS (2.0) API
Without diving into too many details here is a quick overview. In order to execute a method in asynchronous fashion, you just
- need to specify an instance of AsyncResponse interface as one of the method parameters
- annotate it using using the @Suspended annotation (JAX-RS will inject an instance of AsyncResponse for you whenever it detects this annotation)
- need to invoke the request in a different thread – recommended way to do this in Java EE 7 is to use Managed Service Executor
@GET @Produces("text/plain") public void execute(@Suspended AsyncResponse response){ System.out.println("Initially invoked on thread - "+ Thread.currentThread.getName() + ". This will free up soon !"); new Thread(){ @Override public void run(){ response.resume("executed asynchronously on thread - "+ Thread.currentThread.getName()); } }.start(); } //JDK 8 version - passing a Runnable (in form of a Lambda Expression) to a thread @GET @Produces("text/plain") public void execute(@Suspended AsyncResponse response){ System.out.println("Initially invoked on thread - "+ Thread.currentThread.getName() + ". This will free up soon !"); new Thread(() -> response.resume("executed asynchronously on thread - "+ Thread.currentThread().getName())).start(); }
Behind the scenes ??
The underlying I/O connection b/w the server and the client continues to remain open. But there are scenarios where you would want not want the client to wait for a response forever. In such a case, you can allocate a time out (threshold)
The default behavior in case of a time out is a HTTP 503 response. In case you want to override this behavior, you can implement a TimeoutHandler and register it with your AsyncResponse. In case you are using Java 8, you need not bother with a separate implementation class or even an anonymous inner class – you can just provide a Lambda Expression since the TimeoutHandler is a Functional Interface with a Single Abstract Method
@GET @Produces("text/plain") public void execute(@Suspended AsyncResponse response){ System.out.println("Initially invoked on thread - "+ Thread.currentThread.getName() + ". This will free up soon !"); //just having this would result in HTTP 503 after 10 seconds response.setTimeout(10, TimeUnit.SECONDS); //client will recieve a HTTP 408 (timeout error) after 10 seconds response.setTimeoutHandler((asyncResp) -> asyncResp.resume(Response.status(Response.Status.REQUEST_TIMEOUT)).build()); new Thread(() -> { try { Thread.sleep(11000); } catch (InterruptedException ex) { //ignoring } }).start(); }
Cheers!
Reference: | Handling time outs in Async requests in JAX-RS from our JCG partner Abhishek Gupta at the Object Oriented.. blog. |