重试基于结果的方法(而不是异常)
Retry a method based on result (instead of exception)
我有一个具有以下签名的方法:
public Optional<String> doSomething() {
...
}
如果我得到一个空的 Optional
我想重试这个方法并且只有在 3 次 return 之后 Optional
.
我查看并找到了 Retryable
spring 注释,但它似乎只适用于异常。
如果可能的话,我想为此使用一个库,并避免:
- 创建并抛出异常。
- 自己写逻辑。
@Retryable
(以及底层的 RetryTemplate
)完全基于异常。
您可以继承 RetryTemplate
,覆盖 doExecute()
以检查 return 值。
您可能必须复制该方法中的大部分代码;它并不是真正为覆盖 retryCallback.doWithRetry()
调用而设计的。
您可以在RetryOperationsInterceptor
中使用自定义RetryTemplate
(在interceptor
属性中指定@Retryable
)。
编辑
当前的 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
字段,只创建一次。
我目前自己为此编写了一个实用程序(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();
}
我一直在使用 failsafe 构建重试。
您可以根据谓词和异常进行重试。
您的代码如下所示:
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
如果您的结果不符合要求,请抛出异常
我有一个具有以下签名的方法:
public Optional<String> doSomething() {
...
}
如果我得到一个空的 Optional
我想重试这个方法并且只有在 3 次 return 之后 Optional
.
我查看并找到了 Retryable
spring 注释,但它似乎只适用于异常。
如果可能的话,我想为此使用一个库,并避免:
- 创建并抛出异常。
- 自己写逻辑。
@Retryable
(以及底层的 RetryTemplate
)完全基于异常。
您可以继承 RetryTemplate
,覆盖 doExecute()
以检查 return 值。
您可能必须复制该方法中的大部分代码;它并不是真正为覆盖 retryCallback.doWithRetry()
调用而设计的。
您可以在RetryOperationsInterceptor
中使用自定义RetryTemplate
(在interceptor
属性中指定@Retryable
)。
编辑
当前的 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
字段,只创建一次。
我目前自己为此编写了一个实用程序(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();
}
我一直在使用 failsafe 构建重试。 您可以根据谓词和异常进行重试。
您的代码如下所示:
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
如果您的结果不符合要求,请抛出异常