public static <T> CompletableFuture<T> timeoutWithNewReturn(CompletableFuture<T> detectCf, int delay,
        TimeUnit timeUnit, Runnable timeoutAction) {
        if (detectCf.isDone()) {
            return detectCf;
        }
        long timeoutDetectId = TIMEOUT_DETECT_ID_ALLOC.incrementAndGet();
        CompletableFuture<T> newCf = new CompletableFuture<>();
        Timeout timeout = TIMEOUT_DETECT.newTimeout(t -> {
            synchronized (t) {
                LOGGER.info("[TIME_DETECT],{}", timeoutDetectId);
                timeoutAction.run();
                newCf.completeExceptionally(new TimeoutException());
            }
        }, delay, timeUnit);
        detectCf.whenComplete((rst, ex) -> {
            synchronized (timeout) {
                if (timeout.isExpired()) {
                    LOGGER.info("[TIME_DETECT_RECOVERED],{}", timeoutDetectId);
                } else {
                    timeout.cancel();
                    if (ex != null) {
                        newCf.completeExceptionally(ex);
                    } else {
                        newCf.complete(rst);
                    }
                }
            }
        });
        return newCf;
    }
Catch exceptions as a last resort to avoid unresponsiveness.
s3stream/src/main/java/com/automq/stream/utils/FutureUtil.java