CompletableFuture处理超时

在当前的 BatchProcessingService 类中,所有异步任务均通过 CompletableFuture.supplyAsync() 提交,并使用了自定义的 taskExecutor 执行器。但目前 没有实现超时控制,即如果某个任务长时间不完成,也不会中断或返回超时结果。

复制代码
public void processWithTimeout(BatchRequest request,
                                   Consumer<ProcessResult> callback,
                                   CompletableFuture<ProcessResult> completableFuture) {

        CompletableFuture<ProcessResult> future = CompletableFuture.supplyAsync(
                () -> businessService.dealBusiness(request), taskExecutor);

        // 超时 future
        CompletableFuture<ProcessResult> timeoutFuture = CompletableFuture.supplyAsync(() -> {
            try {
                return future.get(5, TimeUnit.SECONDS); // 等待最多5秒
            } catch (TimeoutException e) {
                future.cancel(true); // 尝试取消原任务
                throw new CompletionException(new Exception("处理超时"));
            } catch (Exception e) {
                throw new CompletionException(e);
            }
        }, taskExecutor);

        timeoutFuture.whenComplete((result, throwable) -> {
            if (throwable != null) {
                ProcessResult errorResult = new ProcessResult(
                        request.getId(),
                        false,
                        "处理失败: " + throwable.getMessage(),
                        null,
                        0,
                        (Exception) throwable.getCause()
                );
                callback.accept(errorResult);
                completableFuture.completeExceptionally(throwable);
            } else {
                callback.accept(result);
                completableFuture.complete(result);
            }
        });
    }
  • 手动 get(timeout) 控制增加超时处理

输入API的请求参数如下:

复制代码
[{
    "id":"1"
},
{
    "id":"2"
},
{
    "id":"3"
},
{
    "id":"999"
}]
  • id为999的数据为超时处理
  • 模拟超时的业务代码如下所示:
复制代码
// 模拟处理逻辑
        String id = request.getId();
        Integer idInt = Integer.valueOf(id) == null ? 0 : Integer.valueOf(id);
        // 模拟超时:当ID为特定值时,延迟较长时间
        if (StringUtils.isNoneBlank(id) && idInt == 999) { // 假设999表示需要超时测试
            try {
                Thread.sleep(10000); // 模拟10秒超时
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                return new ProcessResult(
                        request.getId(),
                        false,
                        "处理被中断",
                        null,
                        -1,
                        e
                );
            }
        }

完整代码见上一篇博文