Red Hat Training
A Red Hat training course is available for Red Hat Fuse
48.5.2. 超时和超时处理程序
概述
异步处理模型还支持在 REST 调用时实现超时。默认情况下,超时会导致将 HTTP 错误响应发送到客户端。但是,您还可以选择注册超时处理器回调,它可让您自定义对超时事件的响应。
设置没有处理程序的超时示例
要定义简单的调用超时,但不指定 timeout 处理程序,在 AsyncResponse 对象中调用 setTimeout 方法,如下例所示:
// Java
// Java
...
import java.util.concurrent.TimeUnit;
...
import javax.ws.rs.GET;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.container.AsyncResponse;
import javax.ws.rs.container.Suspended;
import javax.ws.rs.container.TimeoutHandler;
@Path("/bookstore")
public class BookContinuationStore {
...
@GET
@Path("/books/defaulttimeout")
public void getBookDescriptionWithTimeout(@Suspended AsyncResponse async) {
async.setTimeout(2000, TimeUnit.MILLISECONDS);
// Optionally, send request to executor queue for processing
// ...
}
...
}
请注意,您可以使用 java.util.concurrent.TimeUnit 类中的任何单元来指定超时值。前面的示例没有显示将请求发送到 executor 线程池的代码。如果您只想测试超时行为,可以在资源方法正文中包含对 async.SetTimeout 的调用,每次调用时会触发超时。
AsyncResponse.NO_TIMEOUT 值代表无限超时。
默认超时
默认情况下,如果触发调用超时,JAX-RS 运行时会引发 ServiceUnavailableException 异常,并发送 HTTP 错误响应,其状态为 503。
TimeoutHandler 接口
如果要自定义超时行为,您必须通过实施 TimeoutHandler 接口来定义超时处理程序:
// Java
package javax.ws.rs.container;
public interface TimeoutHandler {
public void handleTimeout(AsyncResponse asyncResponse);
}
当您覆盖实现类中的 handleTimeout 方法时,您可以选择以下方法来处理超时:
-
通过调用
asyncResponse.cancel方法取消响应。 -
通过用响应值调用
asyncResponse.resume方法来发送响应。 -
通过调用
asyncResponse.setTimeout方法来扩展等待的时间。(例如,要等待 10 秒,您可以调用asyncResponse.setTimeout (10, TimeUnit.SECONDS))。
使用处理程序设置超时示例
要使用超时处理程序定义调用超时,请在 AsyncResponse 对象中调用 setTimeout Handler 方法和 setTimeoutHandler 方法,如下例所示:
// Java
...
import javax.ws.rs.GET;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.container.AsyncResponse;
import javax.ws.rs.container.Suspended;
import javax.ws.rs.container.TimeoutHandler;
@Path("/bookstore")
public class BookContinuationStore {
...
@GET
@Path("/books/cancel")
public void getBookDescriptionWithCancel(@PathParam("id") String id,
@Suspended AsyncResponse async) {
async.setTimeout(2000, TimeUnit.MILLISECONDS);
async.setTimeoutHandler(new CancelTimeoutHandlerImpl());
// Optionally, send request to executor queue for processing
// ...
}
...
}
在本例中注册一个 CancelTimeoutHandlerImpl timeout 处理程序实例,以处理调用超时。
使用超时处理程序取消响应
CancelTimeoutHandlerImpl timeout 处理程序定义如下:
// Java
...
import javax.ws.rs.container.AsyncResponse;
...
import javax.ws.rs.container.TimeoutHandler;
@Path("/bookstore")
public class BookContinuationStore {
...
private class CancelTimeoutHandlerImpl implements TimeoutHandler {
@Override
public void handleTimeout(AsyncResponse asyncResponse) {
asyncResponse.cancel();
}
}
...
}
在 AsyncResponse 对象上调用 取消 的效果是为客户端发送 HTTP 503 (服务不可用)错误响应。您可以选择为 cancel 方法指定参数( int 或 java.util.Date 值),该值将用于在响应消息中设置 Retry-After: HTTP 标头。但是,客户端通常忽略 Retry-After: 标头。
在可运行的实例中处理取消响应
如果您将暂停请求封装为可运行的实例,它会在 executor 线程池中排队处理,您可能会发现线程池围绕处理请求时已取消 AsyncResponse 已取消。因此,您很难将一些代码添加到可运行的实例,使它能处理已取消的 AsyncResponse 对象。例如:
// Java
...
@Path("/bookstore")
public class BookContinuationStore {
...
private void sendRequestToThreadPool(final String id, final AsyncResponse response) {
executor.execute(new Runnable() {
public void run() {
if ( !response.isCancelled() ) {
// Process the suspended request ...
// ...
}
}
});
}
...
}