异常后自动重试的功能
Functionality for automatic retry after exception
我已将此抽象化 class 以在抛出某些异常时自动重试网络调用。
- 我注意不要在
InterruptedException
之后重试 &
UnknownHostException
。
- 我重试了5次。每次失败后
我执行指数回退,从 300 毫秒开始上升到
1500 毫秒。
public abstract class AutoRetry {
private Object dataToReturn = null;
public Object getDataToReturn() {
return this.dataToReturn;
}
public AutoRetry() {
short retry = -1;
while (retry++ < StaticData.NETWORK_RETRY) {
try {
Thread.sleep(retry * StaticData.NETWORK_CALL_WAIT);
this.dataToReturn = doWork();
break;
} catch (InterruptedException | UnknownHostException e) {
e.printStackTrace();
this.dataToReturn = null;
return;
} catch (IOException e) {
e.printStackTrace();
}
}
}
protected abstract Object doWork() throws IOException;
}
我使用如下:
final Object dataAfterWork = new AutoRetry() {
@Override
protected Object doWork() throws IOException {
return; //a network call which returns something
}
}.getDataToReturn();
这个实现是 good/correct 吗?
编辑
这看起来不错,但我会将 运行 任务与重试分开。也用泛型,不要随便乱扔Object
about.
使用 Java 8
lambda 和方法的 return
:
public static <T> Optional<T> doWithRetry(final Supplier<T> t) {
for (int retry = 0; retry <= StaticData.NETWORK_RETRY; ++retry) {
try {
Thread.sleep(retry * StaticData.NETWORK_CALL_WAIT);
return Optional.of(t.get());
} catch (InterruptedException | UnknownHostException e) {
LOGGER.log(Level.SEVERE, "Call failed.", e);
return Optional.empty();
} catch (IOException e) {
LOGGER.log(Level.WARNING, "Call failed. Retry.", e);
}
}
LOGGER.log(Level.SEVERE, "Call failed. Retries exceeded.");
return Optional.empty();
}
此外,使用 真正的 记录器,而不是 printStackTrace
...
用法:
final String data = doWithRetry(() -> {
//do stuff
});
如果您的 lambda 需要抛出异常,您需要定义自己的 @FunctionalInterface
:
@FunctionalInterface
interface StuffDoer<T> {
T doStuff() throws Exception;
}
并在方法签名中使用它,您需要处理泛型 Exception
。
前Java 8 用法:
final String data = doWithRetry(new StuffDoer<T>() {
@Override
public T get() throws Exception {
return null;
}
});
看看Failsafe。它支持重试策略、同步和异步重试、事件侦听器、与 Java 8 的 CompletableFuture 集成等。例如:
RetryPolicy retryPolicy = new RetryPolicy()
.retryOn(ConnectException.class)
.withDelay(1, TimeUnit.SECONDS)
.withMaxRetries(100);
// Synchronous get with retries
Connection connection = Failsafe.with(retryPolicy).get(() -> connect());
// Asynchronous get with retries
Failsafe.with(retryPolicy, executor)
.get(() -> connect())
.onSuccess(connection -> log.info("Connected to {}", connection))
.onFailure(failure -> log.error("Connection attempts failed", failure));
我已将此抽象化 class 以在抛出某些异常时自动重试网络调用。
- 我注意不要在
InterruptedException
之后重试 &UnknownHostException
。 - 我重试了5次。每次失败后 我执行指数回退,从 300 毫秒开始上升到 1500 毫秒。
public abstract class AutoRetry {
private Object dataToReturn = null;
public Object getDataToReturn() {
return this.dataToReturn;
}
public AutoRetry() {
short retry = -1;
while (retry++ < StaticData.NETWORK_RETRY) {
try {
Thread.sleep(retry * StaticData.NETWORK_CALL_WAIT);
this.dataToReturn = doWork();
break;
} catch (InterruptedException | UnknownHostException e) {
e.printStackTrace();
this.dataToReturn = null;
return;
} catch (IOException e) {
e.printStackTrace();
}
}
}
protected abstract Object doWork() throws IOException;
}
我使用如下:
final Object dataAfterWork = new AutoRetry() {
@Override
protected Object doWork() throws IOException {
return; //a network call which returns something
}
}.getDataToReturn();
这个实现是 good/correct 吗?
编辑
这看起来不错,但我会将 运行 任务与重试分开。也用泛型,不要随便乱扔Object
about.
使用 Java 8
lambda 和方法的 return
:
public static <T> Optional<T> doWithRetry(final Supplier<T> t) {
for (int retry = 0; retry <= StaticData.NETWORK_RETRY; ++retry) {
try {
Thread.sleep(retry * StaticData.NETWORK_CALL_WAIT);
return Optional.of(t.get());
} catch (InterruptedException | UnknownHostException e) {
LOGGER.log(Level.SEVERE, "Call failed.", e);
return Optional.empty();
} catch (IOException e) {
LOGGER.log(Level.WARNING, "Call failed. Retry.", e);
}
}
LOGGER.log(Level.SEVERE, "Call failed. Retries exceeded.");
return Optional.empty();
}
此外,使用 真正的 记录器,而不是 printStackTrace
...
用法:
final String data = doWithRetry(() -> {
//do stuff
});
如果您的 lambda 需要抛出异常,您需要定义自己的 @FunctionalInterface
:
@FunctionalInterface
interface StuffDoer<T> {
T doStuff() throws Exception;
}
并在方法签名中使用它,您需要处理泛型 Exception
。
前Java 8 用法:
final String data = doWithRetry(new StuffDoer<T>() {
@Override
public T get() throws Exception {
return null;
}
});
看看Failsafe。它支持重试策略、同步和异步重试、事件侦听器、与 Java 8 的 CompletableFuture 集成等。例如:
RetryPolicy retryPolicy = new RetryPolicy()
.retryOn(ConnectException.class)
.withDelay(1, TimeUnit.SECONDS)
.withMaxRetries(100);
// Synchronous get with retries
Connection connection = Failsafe.with(retryPolicy).get(() -> connect());
// Asynchronous get with retries
Failsafe.with(retryPolicy, executor)
.get(() -> connect())
.onSuccess(connection -> log.info("Connected to {}", connection))
.onFailure(failure -> log.error("Connection attempts failed", failure));