Initial commit of code for Spring Boot Resilience4j RateLimiter article

This commit is contained in:
Saajan
2021-08-30 16:43:47 +05:30
parent d0b88ace16
commit 154453808d
5 changed files with 319 additions and 0 deletions

View File

@@ -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/)

View File

@@ -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));
}
}

View File

@@ -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);
}
}

View File

@@ -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();
}
}

View File

@@ -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: