Initial check in
This commit is contained in:
@@ -14,6 +14,9 @@ public class SpringbootResilience4jApplication {
|
||||
@Autowired
|
||||
private RateLimiterExamplesRunner rateLimiterExamplesRunner;
|
||||
|
||||
@Autowired
|
||||
private TimeLimiterExamplesRunner timeLimiterExamplesRunner;
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SpringbootResilience4jApplication.class, args);
|
||||
}
|
||||
@@ -22,5 +25,6 @@ public class SpringbootResilience4jApplication {
|
||||
public void runExamples() {
|
||||
retryExamplesRunner.run();
|
||||
rateLimiterExamplesRunner.run();
|
||||
timeLimiterExamplesRunner.run();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
package io.reflectoring.resilience4j.springboot;
|
||||
|
||||
import io.reflectoring.resilience4j.springboot.model.Flight;
|
||||
import io.reflectoring.resilience4j.springboot.model.SearchRequest;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class TimeLimiterExamplesRunner {
|
||||
|
||||
@Autowired
|
||||
private TimeLimitingService service;
|
||||
|
||||
private DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss SSS");
|
||||
|
||||
public static void main(String[] args) {
|
||||
TimeLimiterExamplesRunner runner = new TimeLimiterExamplesRunner();
|
||||
runner.run();
|
||||
}
|
||||
|
||||
static void delay(int seconds) {
|
||||
// sleep to simulate delay
|
||||
try {
|
||||
Thread.sleep(seconds * 1000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void run() {
|
||||
System.out.println("Running timelimiter examples");
|
||||
|
||||
System.out.println(
|
||||
"----------------------- basicExample ----------------------------------------------------");
|
||||
basicExample();
|
||||
|
||||
delay(2); // delay just to let the above async operation to complete
|
||||
|
||||
System.out.println(
|
||||
"----------------------------------------------------------------------------------------------------");
|
||||
|
||||
System.out.println("----------------------- timeoutExample ----------------------------------------------");
|
||||
timeoutExample();
|
||||
|
||||
delay(2); // delay just to let the above async operation to complete
|
||||
|
||||
System.out.println("----------------------------------------------------------------------------------------------------");
|
||||
|
||||
System.out.println("----------------------- fallbackExample ----------------------------------------------");
|
||||
fallbackExample();
|
||||
|
||||
delay(2); // delay just to let the above async operation to complete
|
||||
|
||||
System.out.println("----------------------------------------------------------------------------------------------------");
|
||||
|
||||
System.out.println(
|
||||
"----------------------- eventsExample ----------------------------------------------------");
|
||||
eventsExample();
|
||||
delay(10); // delay just to let the above async operation to complete
|
||||
System.out.println(
|
||||
"----------------------------------------------------------------------------------------------------");
|
||||
}
|
||||
|
||||
private void eventsExample() {
|
||||
SearchRequest request = new SearchRequest("NYC", "LAX", "10/30/2021");
|
||||
for (int i = 0; i < 10; i++) {
|
||||
int attempt = i;
|
||||
service.eventsExample(request)
|
||||
.whenComplete((r, t) -> {
|
||||
if (t != null) {
|
||||
System.out.println("Error occurred on search " + attempt + ": " + t.getMessage());
|
||||
}
|
||||
if (r != null) {
|
||||
System.out
|
||||
.println("Search " + attempt + " successful, found " + r.size() + " flights");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void timeoutExample() {
|
||||
SearchRequest request = new SearchRequest("NYC", "LAX", "10/30/2021");
|
||||
System.out.println("Calling search; current thread = " + Thread.currentThread().getName());
|
||||
CompletableFuture<List<Flight>> results = service.timeoutExample(request);
|
||||
results.whenComplete((result, ex) -> {
|
||||
if (ex != null) {
|
||||
System.out.println("Exception " +
|
||||
ex.getMessage() +
|
||||
" on thread " +
|
||||
Thread.currentThread().getName() +
|
||||
" at " +
|
||||
LocalDateTime.now().format(formatter));
|
||||
ex.printStackTrace();
|
||||
}
|
||||
if (result != null) {
|
||||
System.out.println(result + " on thread " + Thread.currentThread().getName());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void basicExample() {
|
||||
SearchRequest request = new SearchRequest("NYC", "LAX", "10/30/2021");
|
||||
System.out.println("Calling search; current thread = " + Thread.currentThread().getName());
|
||||
CompletableFuture<List<Flight>> results = service.basicExample(request);
|
||||
results.whenComplete((result, ex) -> {
|
||||
if (ex != null) {
|
||||
System.out.println("Exception " +
|
||||
ex.getMessage() +
|
||||
" on thread " +
|
||||
Thread.currentThread().getName() +
|
||||
" at " +
|
||||
LocalDateTime.now().format(formatter));
|
||||
}
|
||||
if (result != null) {
|
||||
System.out.println(result + " on thread " + Thread.currentThread().getName());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void fallbackExample() {
|
||||
SearchRequest request = new SearchRequest("NYC", "LAX", "10/30/2021");
|
||||
System.out.println("Calling search; current thread = " + Thread.currentThread().getName());
|
||||
CompletableFuture<List<Flight>> results = service.fallbackExample(request);
|
||||
results.whenComplete((result, ex) -> {
|
||||
if (ex != null) {
|
||||
System.out.println("Exception " +
|
||||
ex.getMessage() +
|
||||
" on thread " +
|
||||
Thread.currentThread().getName() +
|
||||
" at " +
|
||||
LocalDateTime.now().format(formatter));
|
||||
}
|
||||
if (result != null) {
|
||||
System.out.println(result + " on thread " + Thread.currentThread().getName());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
package io.reflectoring.resilience4j.springboot;
|
||||
|
||||
import io.github.resilience4j.micrometer.tagged.TaggedTimeLimiterMetrics;
|
||||
import io.github.resilience4j.ratelimiter.RequestNotPermitted;
|
||||
import io.github.resilience4j.ratelimiter.annotation.RateLimiter;
|
||||
import io.github.resilience4j.timelimiter.TimeLimiter.EventPublisher;
|
||||
import io.github.resilience4j.timelimiter.TimeLimiterConfig;
|
||||
import io.github.resilience4j.timelimiter.TimeLimiterRegistry;
|
||||
import io.github.resilience4j.timelimiter.annotation.TimeLimiter;
|
||||
import io.micrometer.core.instrument.Measurement;
|
||||
import io.micrometer.core.instrument.Meter;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
|
||||
import io.reflectoring.resilience4j.springboot.model.Flight;
|
||||
import io.reflectoring.resilience4j.springboot.model.SearchRequest;
|
||||
import io.reflectoring.resilience4j.springboot.services.FlightSearchService;
|
||||
import java.sql.Time;
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.StreamSupport;
|
||||
import javax.annotation.PostConstruct;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class TimeLimitingService {
|
||||
@Autowired
|
||||
private FlightSearchService remoteSearchService;
|
||||
|
||||
@Autowired
|
||||
private TimeLimiterRegistry timeLimiterRegistry;
|
||||
|
||||
/*
|
||||
void printDefaultValues() {
|
||||
TimeLimiterConfig config = TimeLimiterConfig.ofDefaults();
|
||||
|
||||
System.out.println(
|
||||
"getTimeoutDuration in ms = " + Duration.from(config.getTimeoutDuration()).toMillis());
|
||||
System.out.println("shouldCancelRunningFuture = " + config.shouldCancelRunningFuture());
|
||||
} */
|
||||
|
||||
|
||||
@TimeLimiter(name = "basicExample")
|
||||
CompletableFuture<List<Flight>> basicExample(SearchRequest request) {
|
||||
return CompletableFuture.supplyAsync(() -> remoteSearchService.searchFlightsTakingOneSecond(request));
|
||||
}
|
||||
|
||||
@TimeLimiter(name = "timeoutExample")
|
||||
CompletableFuture<List<Flight>> timeoutExample(SearchRequest request) {
|
||||
return CompletableFuture.supplyAsync(() -> remoteSearchService.searchFlightsTakingOneSecond(request));
|
||||
}
|
||||
|
||||
@TimeLimiter(name = "timeAndRateLimiter")
|
||||
@RateLimiter(name = "timeAndRateLimiter")
|
||||
CompletableFuture<List<Flight>> aspectOrderExample(SearchRequest request) {
|
||||
return CompletableFuture.supplyAsync(() -> remoteSearchService.searchFlightsTakingOneSecond(request));
|
||||
}
|
||||
|
||||
/*
|
||||
void basicExample_ExcecuteCompletionStage() {
|
||||
TimeLimiterConfig config = TimeLimiterConfig.custom()
|
||||
.timeoutDuration(Duration.ofMillis(500))
|
||||
.build();
|
||||
|
||||
TimeLimiterRegistry registry = TimeLimiterRegistry.of(config);
|
||||
TimeLimiter limiter = registry.timeLimiter("flightSearch");
|
||||
|
||||
FlightSearchService service = new FlightSearchService();
|
||||
SearchRequest request = new SearchRequest("NYC", "LAX", "08/30/2020");
|
||||
|
||||
Supplier<List<Flight>> flightSupplier = () -> service.searchFlightsTakingOneSecond(request);
|
||||
Supplier<CompletionStage<List<Flight>>> origCompletionStageSupplier = () -> CompletableFuture
|
||||
.supplyAsync(flightSupplier);
|
||||
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
|
||||
CompletionStage<List<Flight>> decoratedCompletionStage = limiter
|
||||
.executeCompletionStage(scheduler, origCompletionStageSupplier);
|
||||
|
||||
decoratedCompletionStage.whenComplete((result, ex) -> {
|
||||
if (ex != null) {
|
||||
System.out.println("Exception " +
|
||||
ex.getMessage() +
|
||||
" on thread " +
|
||||
Thread.currentThread().getName() +
|
||||
" at " +
|
||||
LocalDateTime.now().format(formatter));
|
||||
}
|
||||
if (result != null) {
|
||||
System.out.println(result + " on thread " + Thread.currentThread().getName());
|
||||
}
|
||||
});
|
||||
|
||||
scheduler.shutdown();
|
||||
}
|
||||
|
||||
|
||||
void whenToUseExample() {
|
||||
CompletableFuture.supplyAsync(this::slowMethod).thenAccept(System.out::println);
|
||||
}
|
||||
|
||||
void whenToUseExample_Blocking()
|
||||
throws InterruptedException, ExecutionException, TimeoutException {
|
||||
CompletableFuture<Integer> completableFuture = CompletableFuture
|
||||
.supplyAsync(this::slowMethod);
|
||||
Integer result = completableFuture.get(3000, TimeUnit.MILLISECONDS);
|
||||
System.out.println(result);
|
||||
}
|
||||
|
||||
int slowMethod() {
|
||||
System.out.println(Thread.currentThread().getName());
|
||||
// sleep to simulate delay
|
||||
try {
|
||||
Thread.sleep(2000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void delay(int seconds) {
|
||||
// sleep to simulate delay
|
||||
try {
|
||||
Thread.sleep(seconds * 1000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} */
|
||||
|
||||
@TimeLimiter(name = "eventsExample")
|
||||
CompletableFuture<List<Flight>> eventsExample(SearchRequest request) {
|
||||
return CompletableFuture.supplyAsync(() -> remoteSearchService.searchFlightsTakingRandomTime(request));
|
||||
}
|
||||
|
||||
@TimeLimiter(name = "fallbackExample", fallbackMethod = "localCacheFlightSearch")
|
||||
CompletableFuture<List<Flight>> fallbackExample(SearchRequest request) {
|
||||
return CompletableFuture.supplyAsync(() -> remoteSearchService.searchFlightsTakingOneSecond(request));
|
||||
}
|
||||
|
||||
private CompletableFuture<List<Flight>> localCacheFlightSearch(SearchRequest request, TimeoutException rnp) {
|
||||
System.out.println("Returning search results from cache");
|
||||
System.out.println(rnp.getMessage());
|
||||
CompletableFuture<List<Flight>> result = new CompletableFuture<>();
|
||||
result.complete(Arrays.asList(
|
||||
new Flight("XY 765", request.getFlightDate(), request.getFrom(), request.getTo()),
|
||||
new Flight("XY 781", request.getFlightDate(), request.getFrom(), request.getTo())));
|
||||
return result;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
void postConstruct() {
|
||||
EventPublisher eventPublisher = timeLimiterRegistry.timeLimiter("eventsExample").getEventPublisher();
|
||||
eventPublisher.onSuccess(System.out::println);
|
||||
eventPublisher.onError(System.out::println);
|
||||
eventPublisher.onTimeout(System.out::println);
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@ import java.time.format.DateTimeFormatter;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@@ -20,6 +21,7 @@ public class FlightSearchService {
|
||||
|
||||
PotentialFailure potentialFailure = new NoFailure();
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss SSS");
|
||||
Random random = new Random();
|
||||
|
||||
PotentialFailureCheckedException potentialFailureCheckedException = new NoCheckedExceptionFailure();
|
||||
|
||||
@@ -108,4 +110,42 @@ public class FlightSearchService {
|
||||
response.setFlights(flights);
|
||||
return response;
|
||||
}
|
||||
|
||||
public List<Flight> searchFlightsTakingOneSecond(SearchRequest request) {
|
||||
System.out.println("Searching for flights; "
|
||||
+ "current time = " + LocalDateTime.now().format(formatter) +
|
||||
"; current thread = " + Thread.currentThread().getName());
|
||||
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
List<Flight> flights = Arrays.asList(
|
||||
new Flight("XY 765", request.getFlightDate(), request.getFrom(), request.getTo()),
|
||||
new Flight("XY 746", request.getFlightDate(), request.getFrom(), request.getTo())
|
||||
);
|
||||
System.out.println("Flight search successful at " + LocalDateTime.now().format(formatter));
|
||||
return flights;
|
||||
}
|
||||
|
||||
public List<Flight> searchFlightsTakingRandomTime(SearchRequest request) {
|
||||
long delay = random.nextInt(3000);
|
||||
try {
|
||||
Thread.sleep(delay);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
System.out.println("Searching for flights; "
|
||||
+ "current time = " + LocalDateTime.now().format(formatter) +
|
||||
"; current thread = " + Thread.currentThread().getName());
|
||||
|
||||
List<Flight> flights = Arrays.asList(
|
||||
new Flight("XY 765", request.getFlightDate(), request.getFrom(), request.getTo()),
|
||||
new Flight("XY 746", request.getFlightDate(), request.getFrom(), request.getTo())
|
||||
);
|
||||
System.out.println("Flight search successful");
|
||||
return flights;
|
||||
}
|
||||
}
|
||||
@@ -99,6 +99,25 @@ resilience4j:
|
||||
limitRefreshPeriod: 1s
|
||||
timeoutDuration: 500ms
|
||||
|
||||
timelimiter:
|
||||
instances:
|
||||
|
||||
# TimeLimiter object used in TimeLimitingService.basicExample()
|
||||
basicExample:
|
||||
timeoutDuration: 2s
|
||||
|
||||
# TimeLimiter object used in TimeLimitingService.timeoutExample()
|
||||
timeoutExample:
|
||||
timeoutDuration: 500ms
|
||||
|
||||
# TimeLimiter object used in TimeLimitingService.eventsExample()
|
||||
eventsExample:
|
||||
timeoutDuration: 2s
|
||||
|
||||
# TimeLimiter object used in TimeLimitingService.fallbackExample()
|
||||
fallbackExample:
|
||||
timeoutDuration: 500ms
|
||||
|
||||
management:
|
||||
endpoints:
|
||||
web:
|
||||
|
||||
Reference in New Issue
Block a user