Pipeline-specific timeouts with CompletableFuture#orTimeout and JAX-RS 2.1 📎
CompletableFuture#orTimeout
(>= Java 9) method
"...exceptionally completes this CompletableFuture with a TimeoutException if not otherwise completed before the given timeout. ..."and is therefore well suited to set a pipeline-specific timeout.
The method AsyncResponse#setTimeout
sets the max timeout per request:
import static java.util.concurrent.CompletableFuture.supplyAsync;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.container.AsyncResponse;
import javax.ws.rs.container.Suspended;
import javax.ws.rs.core.Response;
@Path("ping")
public class PingResource {
@GET
public void ping(@Suspended AsyncResponse response) {
response.setTimeout(1, TimeUnit.SECONDS); //global timeout
supplyAsync(this::answer).
thenAccept(response::resume).
orTimeout(100, TimeUnit.MILLISECONDS). //pipeline specific timeout
exceptionally((t) -> handleTimeout(response::resume, t));
}
Void handleTimeout(Consumer<Response> consumer, Throwable t) {
consumer.accept(Response.status(503).
header("cause", "timeout in the pipeline").
header("exception", t.toString()).
build());
return null;
}
public String answer() {
try {
Thread.sleep(200);
return "42 + " + System.currentTimeMillis();
} catch (InterruptedException ex) {
throw new IllegalStateException("cannot sleep");
}
}
}
The request: curl -i http://localhost:8080/completable-timeout/resources/ping
returns:
HTTP/1.1 503 Service Unavailable
X-Powered-By: Servlet/4.0
cause: timeout in the pipeline
exception: java.util.concurrent.TimeoutException
(...)
See you at Java EE 8 / Java 9 / Web Workshops at Munich Airport, Terminal 2 or Virtual Dedicated Workshops / consulting. Is Munich's airport too far? Learn from home: airhacks.io.