BAEL-7001: fixed formatting
This commit is contained in:
parent
06943519f8
commit
210eaf2c0b
@ -5,59 +5,59 @@ import java.util.function.Function;
|
|||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public class RetryCompletableFuture {
|
public class RetryCompletableFuture {
|
||||||
public static <T> CompletableFuture<T> retryTask(Supplier<T> supplier, int maxRetries) {
|
public static <T> CompletableFuture<T> retryTask(Supplier<T> supplier, int maxRetries) {
|
||||||
Supplier<T> retryableSupplier = retryFunction(supplier, maxRetries);
|
Supplier<T> retryableSupplier = retryFunction(supplier, maxRetries);
|
||||||
return CompletableFuture.supplyAsync(retryableSupplier);
|
return CompletableFuture.supplyAsync(retryableSupplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
static <T> Supplier<T> retryFunction(Supplier<T> supplier, int maxRetries) {
|
static <T> Supplier<T> retryFunction(Supplier<T> supplier, int maxRetries) {
|
||||||
return () -> {
|
return () -> {
|
||||||
int retries = 0;
|
int retries = 0;
|
||||||
while (retries < maxRetries) {
|
while (retries < maxRetries) {
|
||||||
try {
|
try {
|
||||||
return supplier.get();
|
return supplier.get();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
retries++;
|
retries++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new IllegalStateException(String.format("Task failed after %s attempts", maxRetries));
|
throw new IllegalStateException(String.format("Task failed after %s attempts", maxRetries));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> CompletableFuture<T> retryUnsafe(Supplier<T> supplier, int maxRetries) {
|
public static <T> CompletableFuture<T> retryUnsafe(Supplier<T> supplier, int maxRetries) {
|
||||||
CompletableFuture<T> cf = CompletableFuture.supplyAsync(supplier);
|
CompletableFuture<T> cf = CompletableFuture.supplyAsync(supplier);
|
||||||
sleep(100l);
|
sleep(100l);
|
||||||
for (int i = 0; i < maxRetries; i++) {
|
for (int i = 0; i < maxRetries; i++) {
|
||||||
cf = cf.exceptionally(__ -> supplier.get());
|
cf = cf.exceptionally(__ -> supplier.get());
|
||||||
}
|
}
|
||||||
return cf;
|
return cf;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> CompletableFuture<T> retryNesting(Supplier<T> supplier, int maxRetries) {
|
public static <T> CompletableFuture<T> retryNesting(Supplier<T> supplier, int maxRetries) {
|
||||||
CompletableFuture<T> cf = CompletableFuture.supplyAsync(supplier);
|
CompletableFuture<T> cf = CompletableFuture.supplyAsync(supplier);
|
||||||
sleep(100);
|
sleep(100);
|
||||||
for (int i = 0; i < maxRetries; i++) {
|
for (int i = 0; i < maxRetries; i++) {
|
||||||
cf = cf.thenApply(CompletableFuture::completedFuture)
|
cf = cf.thenApply(CompletableFuture::completedFuture)
|
||||||
.exceptionally(__ -> CompletableFuture.supplyAsync(supplier))
|
.exceptionally(__ -> CompletableFuture.supplyAsync(supplier))
|
||||||
.thenCompose(Function.identity());
|
.thenCompose(Function.identity());
|
||||||
}
|
}
|
||||||
return cf;
|
return cf;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> CompletableFuture<T> retryExceptionallyAsync(Supplier<T> supplier, int maxRetries) {
|
public static <T> CompletableFuture<T> retryExceptionallyAsync(Supplier<T> supplier, int maxRetries) {
|
||||||
CompletableFuture<T> cf = CompletableFuture.supplyAsync(supplier);
|
CompletableFuture<T> cf = CompletableFuture.supplyAsync(supplier);
|
||||||
sleep(100);
|
sleep(100);
|
||||||
for (int i = 0; i < maxRetries; i++) {
|
for (int i = 0; i < maxRetries; i++) {
|
||||||
cf = cf.exceptionallyAsync(__ -> supplier.get());
|
cf = cf.exceptionallyAsync(__ -> supplier.get());
|
||||||
}
|
}
|
||||||
return cf;
|
return cf;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void sleep(long millis) {
|
private static void sleep(long millis) {
|
||||||
try {
|
try {
|
||||||
Thread.sleep(millis);
|
Thread.sleep(millis);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,125 +1,127 @@
|
|||||||
package com.baeldung.concurrent.completablefuture.retry;
|
package com.baeldung.concurrent.completablefuture.retry;
|
||||||
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import static com.baeldung.concurrent.completablefuture.retry.RetryCompletableFuture.retryExceptionallyAsync;
|
||||||
import org.junit.jupiter.api.Test;
|
import static com.baeldung.concurrent.completablefuture.retry.RetryCompletableFuture.retryNesting;
|
||||||
|
import static com.baeldung.concurrent.completablefuture.retry.RetryCompletableFuture.retryTask;
|
||||||
|
import static com.baeldung.concurrent.completablefuture.retry.RetryCompletableFuture.retryUnsafe;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||||
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.CompletionException;
|
import java.util.concurrent.CompletionException;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import static com.baeldung.concurrent.completablefuture.retry.RetryCompletableFuture.*;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import org.junit.jupiter.api.Test;
|
||||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
|
||||||
|
|
||||||
class RetryCompletableFutureUnitTest {
|
class RetryCompletableFutureUnitTest {
|
||||||
private AtomicInteger retriesCounter = new AtomicInteger(0);
|
private AtomicInteger retriesCounter = new AtomicInteger(0);
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void beforeEach() {
|
void beforeEach() {
|
||||||
retriesCounter.set(0);
|
retriesCounter.set(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void whenRetryingTask_thenReturnsCorrectlyAfterFourInvocations() {
|
void whenRetryingTask_thenReturnsCorrectlyAfterFourInvocations() {
|
||||||
Supplier<Integer> codeToRun = () -> failFourTimesThenReturn(100);
|
Supplier<Integer> codeToRun = () -> failFourTimesThenReturn(100);
|
||||||
|
|
||||||
CompletableFuture<Integer> result = retryTask(codeToRun, 10);
|
CompletableFuture<Integer> result = retryTask(codeToRun, 10);
|
||||||
|
|
||||||
assertThat(result.join())
|
assertThat(result.join())
|
||||||
.isEqualTo(100);
|
.isEqualTo(100);
|
||||||
assertThat(retriesCounter)
|
assertThat(retriesCounter)
|
||||||
.hasValue(4);
|
.hasValue(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void whenRetryingTask_thenThrowsExceptionAfterThreeInvocations() {
|
void whenRetryingTask_thenThrowsExceptionAfterThreeInvocations() {
|
||||||
Supplier<Integer> codeToRun = () -> failFourTimesThenReturn(100);
|
Supplier<Integer> codeToRun = () -> failFourTimesThenReturn(100);
|
||||||
|
|
||||||
CompletableFuture<Integer> result = retryTask(codeToRun, 3);
|
CompletableFuture<Integer> result = retryTask(codeToRun, 3);
|
||||||
|
|
||||||
assertThatThrownBy(result::join)
|
assertThatThrownBy(result::join).isInstanceOf(CompletionException.class)
|
||||||
.isInstanceOf(CompletionException.class)
|
.hasMessageContaining("IllegalStateException: Task failed after 3 attempts");
|
||||||
.hasMessageContaining("IllegalStateException: Task failed after 3 attempts");
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void whenRetryingExceptionally_thenReturnsCorrectlyAfterFourInvocations() {
|
void whenRetryingExceptionally_thenReturnsCorrectlyAfterFourInvocations() {
|
||||||
Supplier<Integer> codeToRun = () -> failFourTimesThenReturn(100);
|
Supplier<Integer> codeToRun = () -> failFourTimesThenReturn(100);
|
||||||
|
|
||||||
CompletableFuture<Integer> result = retryUnsafe(codeToRun, 10);
|
CompletableFuture<Integer> result = retryUnsafe(codeToRun, 10);
|
||||||
|
|
||||||
assertThat(result.join())
|
assertThat(result.join())
|
||||||
.isEqualTo(100);
|
.isEqualTo(100);
|
||||||
assertThat(retriesCounter)
|
assertThat(retriesCounter)
|
||||||
.hasValue(4);
|
.hasValue(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void whenRetryingExceptionally_thenThrowsExceptionAfterThreeInvocations() {
|
void whenRetryingExceptionally_thenThrowsExceptionAfterThreeInvocations() {
|
||||||
Supplier<Integer> codeToRun = () -> failFourTimesThenReturn(100);
|
Supplier<Integer> codeToRun = () -> failFourTimesThenReturn(100);
|
||||||
|
|
||||||
CompletableFuture<Integer> result = retryUnsafe(codeToRun, 3);
|
CompletableFuture<Integer> result = retryUnsafe(codeToRun, 3);
|
||||||
|
|
||||||
assertThatThrownBy(result::join)
|
assertThatThrownBy(result::join)
|
||||||
.isInstanceOf(CompletionException.class)
|
.isInstanceOf(CompletionException.class)
|
||||||
.hasMessageContaining("RuntimeException: task failed for 3 time(s)");
|
.hasMessageContaining("RuntimeException: task failed for 3 time(s)");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void whenRetryingExceptionallyAsync_thenReturnsCorrectlyAfterFourInvocations() {
|
void whenRetryingExceptionallyAsync_thenReturnsCorrectlyAfterFourInvocations() {
|
||||||
Supplier<Integer> codeToRun = () -> failFourTimesThenReturn(100);
|
Supplier<Integer> codeToRun = () -> failFourTimesThenReturn(100);
|
||||||
|
|
||||||
CompletableFuture<Integer> result = retryExceptionallyAsync(codeToRun, 10);
|
CompletableFuture<Integer> result = retryExceptionallyAsync(codeToRun, 10);
|
||||||
|
|
||||||
assertThat(result.join())
|
assertThat(result.join())
|
||||||
.isEqualTo(100);
|
.isEqualTo(100);
|
||||||
assertThat(retriesCounter)
|
assertThat(retriesCounter)
|
||||||
.hasValue(4);
|
.hasValue(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void whenRetryingExceptionallyAsync_thenThrowsExceptionAfterThreeInvocations() {
|
void whenRetryingExceptionallyAsync_thenThrowsExceptionAfterThreeInvocations() {
|
||||||
Supplier<Integer> codeToRun = () -> failFourTimesThenReturn(100);
|
Supplier<Integer> codeToRun = () -> failFourTimesThenReturn(100);
|
||||||
|
|
||||||
CompletableFuture<Integer> result = retryExceptionallyAsync(codeToRun, 3);
|
CompletableFuture<Integer> result = retryExceptionallyAsync(codeToRun, 3);
|
||||||
|
|
||||||
assertThatThrownBy(result::join)
|
assertThatThrownBy(result::join)
|
||||||
.isInstanceOf(CompletionException.class)
|
.isInstanceOf(CompletionException.class)
|
||||||
.hasMessageContaining("RuntimeException: task failed for 3 time(s)");
|
.hasMessageContaining("RuntimeException: task failed for 3 time(s)");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void whenRetryingNesting_thenReturnsCorrectlyAfterFourInvocations() {
|
void whenRetryingNesting_thenReturnsCorrectlyAfterFourInvocations() {
|
||||||
Supplier<Integer> codeToRun = () -> failFourTimesThenReturn(100);
|
Supplier<Integer> codeToRun = () -> failFourTimesThenReturn(100);
|
||||||
|
|
||||||
CompletableFuture<Integer> result = retryNesting(codeToRun, 10);
|
CompletableFuture<Integer> result = retryNesting(codeToRun, 10);
|
||||||
|
|
||||||
assertThat(result.join())
|
assertThat(result.join())
|
||||||
.isEqualTo(100);
|
.isEqualTo(100);
|
||||||
assertThat(retriesCounter)
|
assertThat(retriesCounter)
|
||||||
.hasValue(4);
|
.hasValue(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void whenRetryingNesting_thenThrowsExceptionAfterThreeInvocations() {
|
void whenRetryingNesting_thenThrowsExceptionAfterThreeInvocations() {
|
||||||
Supplier<Integer> codeToRun = () -> failFourTimesThenReturn(100);
|
Supplier<Integer> codeToRun = () -> failFourTimesThenReturn(100);
|
||||||
|
|
||||||
CompletableFuture<Integer> result = retryNesting(codeToRun, 3);
|
CompletableFuture<Integer> result = retryNesting(codeToRun, 3);
|
||||||
|
|
||||||
assertThatThrownBy(result::join)
|
assertThatThrownBy(result::join)
|
||||||
.isInstanceOf(CompletionException.class)
|
.isInstanceOf(CompletionException.class)
|
||||||
.hasMessageContaining("RuntimeException: task failed for 3 time(s)");
|
.hasMessageContaining("RuntimeException: task failed for 3 time(s)");
|
||||||
}
|
}
|
||||||
|
|
||||||
int failFourTimesThenReturn(int returnValue) {
|
int failFourTimesThenReturn(int returnValue) {
|
||||||
int retryNr = retriesCounter.get();
|
int retryNr = retriesCounter.get();
|
||||||
System.out.println(String.format("invocation: %s, thread: %s", retryNr, Thread.currentThread().getName()));
|
System.out.println(String.format("invocation: %s, thread: %s", retryNr, Thread.currentThread().getName()));
|
||||||
if (retryNr < 4) {
|
if (retryNr < 4) {
|
||||||
retriesCounter.set(retryNr + 1);
|
retriesCounter.set(retryNr + 1);
|
||||||
throw new RuntimeException(String.format("task failed for %s time(s)", retryNr));
|
throw new RuntimeException(String.format("task failed for %s time(s)", retryNr));
|
||||||
}
|
}
|
||||||
return returnValue;
|
return returnValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user