java—基于结果(而不是异常)重试方法

wydwbb8l  于 2021-07-12  发布在  Java
关注(0)|答案(4)|浏览(462)

我有一个签名如下的方法:

public Optional<String> doSomething() {
    ...
}

如果我得到一个空的 Optional 我想重试这个方法,只在3次后返回空的 Optional .
我已经找过了 Retryable spring注解,但它似乎只适用于异常。
如果可能的话,我想使用一个库来实现这一点,并避免:
创建并引发异常。
我自己写逻辑。

juzqafwq

juzqafwq1#

我一直在使用故障保护内置重试。可以基于 predicate 和异常重试。
您的代码如下所示:

private Optional<String> doSomethingWithRetry() {
        RetryPolicy<Optional> retryPolicy = new RetryPolicy<Optional>()
                .withMaxAttempts(3)
                .handleResultIf(result -> {
                    System.out.println("predicate");
                    return !result.isPresent();
                });

        return Failsafe
                .with(retryPolicy)
                .onSuccess(response -> System.out.println("ok"))
                .onFailure(response -> System.out.println("no ok"))
                .get(() -> doSomething());
    }

    private Optional<String> doSomething() {
         return Optional.of("result");
    }

如果可选值不为空,则输出为:

predicate
ok

否则看起来像:

predicate
predicate
predicate
no ok
5cnsuln7

5cnsuln72#

我目前自己为此编写了一个util(vanilla java),其他答案非常受欢迎:

import java.util.function.Predicate;
import java.util.function.Supplier;

public class Retryable<T> {
    private Supplier<T> action = () -> null;
    private Predicate<T> successCondition = ($) -> true;
    private int numberOfTries = 3;
    private long delay = 1000L;
    private Supplier<T> fallback = () -> null;

    public static <A> Retryable<A> of(Supplier<A> action) {
        return new Retryable<A>().run(action);
    }

    public Retryable<T> run(Supplier<T> action) {
        this.action = action;
        return this;
    }

    public Retryable<T> successIs(Predicate<T> successCondition) {
        this.successCondition = successCondition;
        return this;
    }

    public Retryable<T> retries(int numberOfTries) {
        this.numberOfTries = numberOfTries;
        return this;
    }

    public Retryable<T> delay(long delay) {
        this.delay = delay;
        return this;
    }

    public Retryable<T> orElse(Supplier<T> fallback) {
        this.fallback = fallback;
        return this;
    }

    public T execute() {
        for (int i = 0; i < numberOfTries; i++) {
            T t = action.get();
            if (successCondition.test(t)) {
                return t;
            }

            try {
                Thread.sleep(delay);
            } catch (InterruptedException e) {
                // do nothing
            }
        }
        return fallback.get();
    }
}

使用此代码,我的方法如下所示:

public Optional<String> doSomething() {
    return Retryable
        .of(() -> actualDoSomething())
        .successIs(Optional::isPresent)
        .retries(3)
        .delay(1000L)
        .orElse(Optional::empty)
        .execute();
}
0ejtzxu1

0ejtzxu13#

@Retryable (以及潜在的 RetryTemplate )完全基于例外。
你可以把 RetryTemplate ,覆盖 doExecute() 检查返回值。
您可能需要复制方法中的大部分代码;它并不是专门用来覆盖 retryCallback.doWithRetry() 打电话。
您可以使用自定义 RetryTemplate 在一个 RetryOperationsInterceptor (见 @Retryableinterceptor 属性)。
编辑
电流 RetryTemplate 代码看起来像这样。。。

while (canRetry(retryPolicy, context) && !context.isExhaustedOnly()) {

    try {
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Retry: count=" + context.getRetryCount());
        }
        // Reset the last exception, so if we are successful
        // the close interceptors will not think we failed...
        lastException = null;
        return retryCallback.doWithRetry(context);
    }
    catch (Throwable e) {

        lastException = e;

        try {
            registerThrowable(retryPolicy, state, context, e);
        }
        catch (Exception ex) {
            throw new TerminatedRetryException("Could not register throwable",
                    ex);
        }
        finally {
            doOnErrorInterceptors(retryCallback, context, e);
        }

         ... 

    }

你得把它改成。。。

while (canRetry(retryPolicy, context) && !context.isExhaustedOnly()) {

    try {
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Retry: count=" + context.getRetryCount());
        }
        // Reset the last exception, so if we are successful
        // the close interceptors will not think we failed...
        lastException = null;
        T result = retryCallback.doWithRetry(context);
        if (((Optional<String>) result).get() == null) {

            try {
                registerThrowable(retryPolicy, state, context, someDummyException);
            }
            catch (Exception ex) {
                throw new TerminatedRetryException("Could not register throwable",
                        ex);
            }
            finally {
                doOnErrorInterceptors(retryCallback, context, e);
            }

            ...
        }
        else {
            return result;
        }
    }
    catch (Throwable e) {

       ...

    }

哪里 someDummyException 就是欺骗上下文使计数器递增。它可以是一个 static 字段,只创建了一次。

6ioyuze2

6ioyuze24#

如果结果不理想,就抛出异常

相关问题