当函数在 y 时间间隔内抛出异常时重试函数调用 n 次

Rah*_*and 2 java schedule scheduled-tasks java-8 retry-logic

我想在一段时间内失败时重试我的函数调用。这样做的最佳方法是什么。这会正常工作吗。

CompletableFuture.runAsync(() -> {
    for (int i = 0; i < 3; i++) {
        try {
            dndService.initateDNDRequest(transactionId, circle, category, "PREPAID");       
            break;
        } catch (Exception e) {
            try {
                TimeUnit.SECONDS.sleep(10);//wait for few minutes while next attempt
            } catch (InterruptedException e1) {
                LOGGER.error("Error while retrying request for DND.");
            }
            LOGGER.error("Request retry for DND count"+i);
        }
    }
}, executor);
Run Code Online (Sandbox Code Playgroud)

Hol*_*ger 5

你不应该把一个执行者的工作线程放到sleep.

安排新尝试的一种解决方案是

    Executor executor; // … the actual executor
    ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor();
    Executor afterTenSeconds
        = r -> ses.schedule(() -> executor.execute(r), 10, TimeUnit.SECONDS);

    Runnable primaryAction
        = () -> dndService.initateDNDRequest(transactionId, circle, category, "PREPAID");

    CompletableFuture<Void> cf = CompletableFuture.runAsync(primaryAction, executor);
    for(int i = 0; i < 3; i++) {
        cf = cf.handle((v,t) -> t == null? CompletableFuture.completedFuture(v):
                                CompletableFuture.runAsync(primaryAction, afterTenSeconds))
               .thenCompose(Function.identity());
    }
Run Code Online (Sandbox Code Playgroud)

然后handleaction 将安排新的尝试,在失败情况下超时(十秒)后执行。这thenCompose(Function.identity())是必要的,因为没有单一的方法来组合handlecompose语义。

请注意,从 Java 9 开始,您可以像创建延迟执行器一样简单

Executor afterTenSeconds = CompletableFuture.delayedExecutor(10,TimeUnit.SECONDS,executor);
Run Code Online (Sandbox Code Playgroud)

无需处理ScheduledExecutorService自己。