我为我的API使用Java 1.8,dropwizard 1.3.5和大张旗鼓的变化1.0.13。
我有一个方法,它需要一个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;
}
说,如果操作(在这种情况下需要20秒)超过15秒,我想返回400状态代码。我将如何实现?
答案 0 :(得分:4)
您可以使用Google Guava库中的TimeLimiter之类的东西。这允许您将可调用对象包装在可以使用超时调用的操作中。如果可调用对象未及时完成操作,它将抛出一个TimeoutException
,您可以捕获并返回400响应。
例如:
TimeLimiter timeLimiter = new SimpleTimeLimiter();
try {
String result = timeLimiter.callWithTimeout(
() -> doSomeHeavyWeightOperation(), 15, TimeUnit.SECONDS);
} catch (TimeoutException e) {
// return 400
}
答案 1 :(得分:4)
一种无需其他库即可完成此操作的方法是使用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
调用中显而易见的那样,我们告诉我们我们愿意等待多少。返回的期货列表将始终包含与任务列表一样多的元素,因此无需检查其是否为空。我们只需要检查任务是否完成即可。