Initial commit of code for Spring Boot Resilience4j RateLimiter article
This commit is contained in:
@@ -5,3 +5,4 @@ Run the SpringbootResilience4jApplication program
|
||||
## Blog posts
|
||||
|
||||
* [Implementing Retry with Spring_Boot_Resilience4j](https://reflectoring.io/retry-with-springboot-resilience4j/)
|
||||
* [Implementing Rate Limiting with Spring_Boot_Resilience4j](https://reflectoring.io/rate-limiting-with-springboot-resilience4j/)
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
package io.reflectoring.resilience4j.springboot;
|
||||
|
||||
import io.reflectoring.resilience4j.springboot.model.SearchRequest;
|
||||
import java.time.Duration;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class RateLimiterExamplesRunner {
|
||||
|
||||
@Autowired
|
||||
private RateLimitingService service;
|
||||
|
||||
public static void main(String[] args) {
|
||||
RateLimiterExamplesRunner runner = new RateLimiterExamplesRunner();
|
||||
runner.run();
|
||||
}
|
||||
|
||||
public void run() {
|
||||
System.out.println("Running ratelimiter examples");
|
||||
|
||||
System.out.println("----------------------------- basicExample ------------------------------------------");
|
||||
basicExample();
|
||||
System.out.println("-----------------------------------------------------------------------");
|
||||
|
||||
System.out.println("----------------------------- timeoutExample ------------------------------------------");
|
||||
timeoutExample();
|
||||
System.out.println("-----------------------------------------------------------------------");
|
||||
|
||||
System.out.println("------------------------------ multipleLimits_2rps_40rpm_sequential -----------------------------------------");
|
||||
multipleLimits_2rps_40rpm_sequential();
|
||||
System.out.println("-----------------------------------------------------------------------");
|
||||
|
||||
System.out.println("------------------------------- changeLimitsExample ----------------------------------------");
|
||||
changeLimitsExample();
|
||||
System.out.println("-----------------------------------------------------------------------");
|
||||
|
||||
System.out.println("------------------------------- retryAndRateLimit ----------------------------------------");
|
||||
retryAndRateLimit();
|
||||
System.out.println("-----------------------------------------------------------------------");
|
||||
|
||||
System.out.println("------------------------------ rateLimiterEvents -----------------------------------------");
|
||||
rateLimiterEvents();
|
||||
System.out.println("-----------------------------------------------------------------------");
|
||||
|
||||
System.out.println("----------------------------- fallbackExample ------------------------------------------");
|
||||
fallbackExample();
|
||||
System.out.println("-----------------------------------------------------------------------");
|
||||
}
|
||||
|
||||
private void rateLimiterEvents() {
|
||||
SearchRequest request = new SearchRequest("NYC", "LAX", "08/15/2021");
|
||||
|
||||
try {
|
||||
System.out.println(service.rateLimiterEventsExample(request));
|
||||
System.out.println(service.rateLimiterEventsExample(request));
|
||||
}
|
||||
catch (Exception e) {
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void retryAndRateLimit() {
|
||||
SearchRequest request = new SearchRequest("NYC", "LAX", "08/15/2021");
|
||||
|
||||
System.out.println(service.retryAndRateLimit(request));
|
||||
System.out.println(service.retryAndRateLimit(request));
|
||||
}
|
||||
|
||||
private void changeLimitsExample() {
|
||||
SearchRequest request = new SearchRequest("NYC", "LAX", "08/15/2021");
|
||||
|
||||
for (int i=0; i<6; i++) {
|
||||
System.out.println(service.changeLimitsExample(request));
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(2000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
service.updateRateLimits("changeLimitsExample", 2, Duration.ofSeconds(2));
|
||||
System.out.println("Rate limits changed");
|
||||
|
||||
for (int i=0; i<6; i++) {
|
||||
System.out.println(service.changeLimitsExample(request));
|
||||
}
|
||||
}
|
||||
|
||||
private void multipleLimits_2rps_40rpm_sequential() {
|
||||
SearchRequest request = new SearchRequest("NYC", "LAX", "08/15/2021");
|
||||
for (int i=0; i<45; i++) {
|
||||
try {
|
||||
System.out.println(service.multipleRateLimitsExample(request));
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void timeoutExample() {
|
||||
SearchRequest request = new SearchRequest("NYC", "LAX", "08/15/2021");
|
||||
try {
|
||||
for (int i=0; i<3; i++) {
|
||||
System.out.println(service.timeoutExample(request));
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void basicExample() {
|
||||
SearchRequest request = new SearchRequest("NYC", "LAX", "08/15/2021");
|
||||
for (int i=0; i<4; i++) {
|
||||
try {
|
||||
System.out.println(service.basicExample(request));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void fallbackExample() {
|
||||
SearchRequest request = new SearchRequest("NYC", "LAX", "08/15/2021");
|
||||
System.out.println(service.fallbackExample(request));
|
||||
System.out.println(service.fallbackExample(request));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
package io.reflectoring.resilience4j.springboot;
|
||||
|
||||
import io.github.resilience4j.ratelimiter.RateLimiterRegistry;
|
||||
import io.github.resilience4j.ratelimiter.RequestNotPermitted;
|
||||
import io.github.resilience4j.ratelimiter.annotation.RateLimiter;
|
||||
import io.github.resilience4j.retry.RetryRegistry;
|
||||
import io.github.resilience4j.retry.annotation.Retry;
|
||||
import io.reflectoring.resilience4j.springboot.model.Flight;
|
||||
import io.reflectoring.resilience4j.springboot.model.SearchRequest;
|
||||
import io.reflectoring.resilience4j.springboot.services.FlightSearchService;
|
||||
import java.time.Duration;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import javax.annotation.PostConstruct;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class RateLimitingService {
|
||||
@Autowired
|
||||
private FlightSearchService remoteSearchService;
|
||||
|
||||
@Autowired
|
||||
private RPMRateLimitedFlightSearchSearch rpmRateLimitedFlightSearchSearch;
|
||||
|
||||
@Autowired
|
||||
private RateLimiterRegistry registry;
|
||||
|
||||
@Autowired
|
||||
private RetryRegistry retryRegistry;
|
||||
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss SSS");
|
||||
|
||||
@RateLimiter(name = "basicExample")
|
||||
List<Flight> basicExample(SearchRequest request) {
|
||||
return remoteSearchService.searchFlights(request);
|
||||
}
|
||||
|
||||
@RateLimiter(name = "timeoutExample")
|
||||
List<Flight> timeoutExample(SearchRequest request) {
|
||||
return remoteSearchService.searchFlights(request);
|
||||
}
|
||||
|
||||
@RateLimiter(name = "multipleRateLimiters_rps_limiter")
|
||||
List<Flight> multipleRateLimitsExample(SearchRequest request) {
|
||||
return rpmRateLimitedFlightSearchSearch.searchFlights(request, remoteSearchService);
|
||||
}
|
||||
|
||||
// doesn't work - @RateLimiter is not a repeatable annotation
|
||||
// @RateLimiter(name = "multipleRateLimiters_rps_limiter")
|
||||
// @RateLimiter(name = "multipleRateLimiters_rpm_limiter")
|
||||
// List<Flight> multipleRateLimitsExample(SearchRequest request) {
|
||||
// return remoteSearchService.searchFlights(request, remoteSearchService);
|
||||
// }
|
||||
|
||||
// doesn't work - calls within a Spring bean don't go thru the Spring proxy
|
||||
// @RateLimiter(name = "multipleRateLimiters_rps_limiter")
|
||||
// List<Flight> rpsLimitedSearch(SearchRequest request) {
|
||||
// return rpmLimitedSearch(request, remoteSearchService);
|
||||
// }
|
||||
|
||||
// @RateLimiter(name = "multipleRateLimiters_rpm_limiter")
|
||||
// List<Flight> rpmLimitedSearch(SearchRequest request) {
|
||||
// return remoteSearchService.searchFlights(request, remoteSearchService);
|
||||
// }
|
||||
|
||||
|
||||
@RateLimiter(name = "changeLimitsExample")
|
||||
public List<Flight> changeLimitsExample(SearchRequest request) {
|
||||
return remoteSearchService.searchFlights(request);
|
||||
}
|
||||
|
||||
@Retry(name = "retryAndRateLimitExample")
|
||||
@RateLimiter(name = "retryAndRateLimitExample")
|
||||
public List<Flight> retryAndRateLimit(SearchRequest request) {
|
||||
return remoteSearchService.searchFlights(request);
|
||||
}
|
||||
|
||||
@RateLimiter(name = "rateLimiterEventsExample")
|
||||
public List<Flight> rateLimiterEventsExample(SearchRequest request) {
|
||||
return remoteSearchService.searchFlights(request);
|
||||
}
|
||||
|
||||
public void updateRateLimits(String rateLimiterName, int newLimitForPeriod, Duration newTimeoutDuration) {
|
||||
io.github.resilience4j.ratelimiter.RateLimiter limiter = registry.rateLimiter(rateLimiterName);
|
||||
limiter.changeLimitForPeriod(newLimitForPeriod);
|
||||
limiter.changeTimeoutDuration(newTimeoutDuration);
|
||||
}
|
||||
|
||||
@RateLimiter(name = "fallbackExample", fallbackMethod = "localCacheFlightSearch")
|
||||
public List<Flight> fallbackExample(SearchRequest request) {
|
||||
return remoteSearchService.searchFlights(request);
|
||||
}
|
||||
|
||||
private List<Flight> localCacheFlightSearch(SearchRequest request, RequestNotPermitted rnp) {
|
||||
System.out.println("Returning search results from cache");
|
||||
return Arrays.asList(
|
||||
new Flight("XY 765", request.getFlightDate(), request.getFrom(), request.getTo()),
|
||||
new Flight("XY 781", request.getFlightDate(), request.getFrom(), request.getTo()));
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void postConstruct() {
|
||||
io.github.resilience4j.retry.Retry.EventPublisher retryEventPublisher = retryRegistry
|
||||
.retry("retryAndRateLimitExample")
|
||||
.getEventPublisher();
|
||||
|
||||
retryEventPublisher.onRetry(System.out::println);
|
||||
retryEventPublisher.onSuccess(System.out::println);
|
||||
|
||||
io.github.resilience4j.ratelimiter.RateLimiter.EventPublisher eventPublisher = registry
|
||||
.rateLimiter("rateLimiterEventsExample")
|
||||
.getEventPublisher();
|
||||
|
||||
eventPublisher.onSuccess(System.out::println);
|
||||
eventPublisher.onFailure(System.out::println);
|
||||
}
|
||||
}
|
||||
|
||||
@Component
|
||||
class RPMRateLimitedFlightSearchSearch {
|
||||
@RateLimiter(name = "multipleRateLimiters_rpm_limiter")
|
||||
List<Flight> searchFlights(SearchRequest request, FlightSearchService remoteSearchService) {
|
||||
return remoteSearchService.searchFlights(request);
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,9 @@ public class SpringbootResilience4jApplication {
|
||||
@Autowired
|
||||
private RetryExamplesRunner retryExamplesRunner;
|
||||
|
||||
@Autowired
|
||||
private RateLimiterExamplesRunner rateLimiterExamplesRunner;
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SpringbootResilience4jApplication.class, args);
|
||||
}
|
||||
@@ -18,5 +21,6 @@ public class SpringbootResilience4jApplication {
|
||||
@EventListener(ApplicationReadyEvent.class)
|
||||
public void runExamples() {
|
||||
retryExamplesRunner.run();
|
||||
rateLimiterExamplesRunner.run();
|
||||
}
|
||||
}
|
||||
@@ -44,6 +44,61 @@ resilience4j:
|
||||
- java.lang.Exception
|
||||
waitDuration: 2s
|
||||
|
||||
# Retry object used in RateLimitingService.retryAndRateLimitExample()
|
||||
retryAndRateLimitExample:
|
||||
maxRetryAttempts: 2
|
||||
waitDuration: 1s
|
||||
|
||||
ratelimiter:
|
||||
instances:
|
||||
|
||||
# RateLimiter object used in RateLimitingService.basicExample()
|
||||
basicExample:
|
||||
limitForPeriod: 1
|
||||
limitRefreshPeriod: 1s
|
||||
timeoutDuration: 1s
|
||||
|
||||
# RateLimiter object used in RateLimitingService.timeoutExample()
|
||||
timeoutExample:
|
||||
limitForPeriod: 1
|
||||
limitRefreshPeriod: 1s
|
||||
timeoutDuration: 250ms
|
||||
|
||||
# RateLimiter object used in RateLimitingService.multipleRateLimitsExample()
|
||||
multipleRateLimiters_rps_limiter:
|
||||
limitForPeriod: 2
|
||||
limitRefreshPeriod: 1s
|
||||
timeoutDuration: 2s
|
||||
|
||||
multipleRateLimiters_rpm_limiter:
|
||||
limitForPeriod: 40
|
||||
limitRefreshPeriod: 1m
|
||||
timeoutDuration: 2s
|
||||
|
||||
# RateLimiter object used in RateLimitingService.changeLimitsExample()
|
||||
changeLimitsExample:
|
||||
limitForPeriod: 1
|
||||
limitRefreshPeriod: 1s
|
||||
timeoutDuration: 1s
|
||||
|
||||
# RateLimiter object used in RateLimitingService.retryAndRateLimitExample()
|
||||
retryAndRateLimitExample:
|
||||
limitForPeriod: 1
|
||||
limitRefreshPeriod: 1s
|
||||
timeoutDuration: 250ms
|
||||
|
||||
# RateLimiter object used in RateLimitingService.rateLimiterEventsExample()
|
||||
rateLimiterEventsExample:
|
||||
limitForPeriod: 1
|
||||
limitRefreshPeriod: 1s
|
||||
timeoutDuration: 50ms
|
||||
|
||||
# RateLimiter object used in RateLimitingService.fallbackExample()
|
||||
fallbackExample:
|
||||
limitForPeriod: 1
|
||||
limitRefreshPeriod: 1s
|
||||
timeoutDuration: 500ms
|
||||
|
||||
management:
|
||||
endpoints:
|
||||
web:
|
||||
|
||||
Reference in New Issue
Block a user