我使用Java 1.8,dropwizard 1.3.5和swagger inflection 1.0.13 for my API。
我有一个方法,它接受HTTP请求,延迟20秒,然后返回200状态代码响应:
public ResponseContext delayBy20Seconds(RequestContext context) {
ResponseContext response = new ResponseContext().contentType(MediaType.APPLICATION_JSON_TYPE);
Thread.sleep(20000);
response.status(Response.Status.OK);
return response;
}
假设我想要返回400状态代码,如果操作(在这种情况下需要20秒),则需要超过15秒。我怎么做到这一点?
没有额外库的一种方法是使用java.util.concurrent
包。取消像这样长时间运行的任务的最可靠方法是在一个单独的线程中运行它。
import java.util.concurrent.*;
...
private ExecutorService exec = Executors.newSingleThreadExecutor();
public ResponseContext delayBy20Seconds(RequestContext context) {
Callable<ResponseContext> task = new Callable<ResponseContext>() {
@Override
public ResponseContext call() throws Exception {
Thread.sleep(20000);
return new ResponseContext().contentType(MediaType.APPLICATION_JSON_TYPE);
}
};
List<Callable<ResponseContext>> tasks = new ArrayList<>();
tasks.add(task);
List<Future<ResponseContext>> done = exec.invokeAll(tasks, 15, TimeUnit.SECONDS);
Future<ResponseContext> task1 = done.get(0);
if (task1.isCancelled()) {
return some Error Response;
}
return task1.get();
}
你的ExecutorService
不应该是静态的,因为你不想在这些特定用途的线程之间共享它。
Callable<ResponseContext>
实现是完成长期任务的工作。正如在exec.invokeAll
电话中应该明显的那样,我们告诉它我们愿意等多少。返回的Futures列表将始终包含与任务列表一样多的元素,因此无需检查它是否空虚。我们只需要检查任务是否完成。
您可以使用Google Guava库中的TimeLimiter之类的东西。这允许您在可以使用Timeout调用的操作中包装可调用对象。如果callable没有及时完成操作,它将抛出一个TimeoutException
,你可以捕获并返回400响应。
举个例子:
TimeLimiter timeLimiter = new SimpleTimeLimiter();
try {
String result = timeLimiter.callWithTimeout(
() -> doSomeHeavyWeightOperation(), 15, TimeUnit.SECONDS);
} catch (TimeoutException e) {
// return 400
}