我有一个带有端点的休息 Controller :
@GET
@Path("/reindex-record")
public String reindexRecord(@QueryParam("id") String id) {
if (StringUtils.isEmpty(id)) {
CompletableFuture.runAsync(
() -> runWithException(Reindexer::reindexAll));
} else {
CompletableFuture.runAsync(() -> runWithException(
() -> Reindexer.reindexOne(id)));
}
// return "ok" or throw WebApplciationException from runWithException method below
}
这是我的包装方法 - 两种方法 - reindexAll 和 reindexOne 都会抛出已检查的异常,因此决定使用包装方法和接口(interface):
public interface RunnableWithException {
void run() throws Exception;
}
private void runWithException(RunnableWithException task) {
try {
task.run();
} catch (Exception e) {
log.error("Error occured during async task execution", e);
throw new WebApplicationException(
Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity("Internal error occurred").build());
}
}
问题是我想使用 CompleteableFuture 异步运行此任务,并且仅在给定任务完成后或者出现错误抛出带有 INTERNAL_SERVER_ERROR 状态的 WebApplicationException 时才给出响应。
您将如何在我的用例中使用 if/else 实现这一点?
编辑: 截至目前我有这个方法:
@GET
@Path("/reindex-record")
public String reindexRecord(@QueryParam("id") String id) throws ExecutionException,
InterruptedException {
CompletableFuture<Void> task;
if (StringUtils.isEmpty(id)) {
task = CompletableFuture.runAsync(
() -> runWithException(Reindexer::reindexAll));
} else {
task = CompletableFuture.runAsync(() -> runWithException(
() -> Reindexer.reindexOne(id)));
}
return task.thenApply(x -> "ok")
.exceptionally(throwable -> {
log.error("Error occured during async task execution", throwable);
throw new WebApplicationException(Response.status(Response.Status.SERVICE_UNAVAILABLE)
.entity("Internal error occurred. Try again later")
.build());
}).get();
}
但是,如果任何 Reindexer 方法抛出错误,我仍然会收到带有数据的状态 500:
{
"code": 500,
"message": "There was an error processing your request. It has been logged (ID 03f09a62b62b1649)."
}
而不是我的异常(exception)
block 中定义的503。
如果重要的话,将 dropwizard 与 JAX-RS 一起使用。
最佳答案
您可以将方法的主体更改为:
@GET
@Path("/reindex-record")
public String reindexRecord(@QueryParam("id") String id) {
final CompletableFuture<Void> future;
if (StringUtils.isEmpty(id)) {
future = CompletableFuture.runAsync(
() -> runWithException(Reindexer::reindexAll));
} else {
future = CompletableFuture.runAsync(
() -> runWithException(() -> Reindexer.reindexOne(id)));
}
// this will block
future.get();
return "ok";
}
通过存储 future,您可以调用它的 get()
方法,该方法将阻塞,直到 future 完成。
来自CompletableFuture.get()
的javadoc:
Waits if necessary for this future to complete, and then returns its result.
关于java - CompleteableFuture 抛出异常时返回 500 内部错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51399766/