Честно говоря, вопрос слишком широкий, потому что ответ действительно зависит от того, какие фреймворки вы уже используете. Дело в том, что сегодня существует много популярных фреймворков, которые обеспечивают реализацию логики повторов прямо из коробки.
Например:
Однако, если после рассмотрения альтернатив вы решили осуществить повторную попытку вручную с помощью CompletableFuture
, вы определенно можете это сделать.
Например, вот простые утилиты для повторной попытки:
- Неограниченное количество раз:
public static <T> CompletableFuture<T> retry(Throwable throwable, Function<Throwable, T> operation) {
return CompletableFuture.supplyAsync(() -> operation.apply(throwable))
.thenApply(CompletableFuture::completedFuture)
.exceptionally(error -> retry(error, operation))
.thenCompose(Function.identity());
}
Примечание: Здесь я предполагаю, что вы можетепринять какое-то решение на основе экземпляра Throwable
. Следовательно, operation
принимает ошибку в качестве входных данных и дает некоторый полезный результат в качестве выходных данных. В вашем случае ошибка - может быть critical API
ошибка вызова или notification error
, полезный результат - успешный critical API
результат.
- Фиксированное число раз (
MAX_RETRIES
в данном случае):
public static <T> CompletableFuture<T> retry(Throwable throwable, Function<Throwable, T> operation, int retry) {
if (retry == MAX_RETRIES) return failedFuture(throwable);
return CompletableFuture.supplyAsync(() -> operation.apply(throwable))
.thenApply(CompletableFuture::completedFuture)
.exceptionally(error -> retry(error, operation, retry + 1))
.thenCompose(Function.identity());
}
public static <T> CompletableFuture<T> failedFuture(Throwable throwable) {
final CompletableFuture<T> failedFuture = new CompletableFuture<>();
failedFuture.completeExceptionally(throwable);
return failedFuture;
}