romeh / spring-cloud-gateway-resilience4j Goto Github PK
View Code? Open in Web Editor NEWSample spring cloud gateway project to show how to use resilience4j as a gateway circuitbreaker
License: Apache License 2.0
Sample spring cloud gateway project to show how to use resilience4j as a gateway circuitbreaker
License: Apache License 2.0
I facing an issue while working on resilience4j circuit breaker with spring cloud gatway (Routes defined in java). Request to help here.
{
"timestamp": "2020-07-01T07:44:45.732+0000",
"path": "/api/gateway/auth/userdetails",
"status": 404,
"error": "Not Found",
"message": null,
"requestId": "fb35d9a5",
"trace": "org.springframework.web.server.ResponseStatusException: 404 NOT_FOUND\r\n\tat org.springframework.web.reactive.resource.ResourceWebHandler.lambda$handle$0(ResourceWebHandler.java:325)\r\n\tSuppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: \nError has been observed at the following site(s):\n\t|_ checkpoint ⇢ com.db.dbipp.diamondca.gateway.interceptor.CustomWebFilter [DefaultWebFilterChain]\n\t|_ checkpoint ⇢ org.springframework.cloud.gateway.filter.WeightCalculatorWebFilter [DefaultWebFilterChain]\n\t|_ checkpoint ⇢ org.springframework.boot.actuate.metrics.web.reactive.server.MetricsWebFilter [DefaultWebFilterChain]\n\t|_ checkpoint ⇢ HTTP GET "/api/gateway/auth/userdetails" [ExceptionHandlingWebHandler]\nStack trace:\r\n\t\tat org.springframework.web.reactive.resource.ResourceWebHandler.lambda$handle$0(ResourceWebHandler.java:325)\r\n\t\tat reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:44)\r\n\t\tat reactor.core.publisher.Mono.subscribe(Mono.java:4105)\r\n\t\tat reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onComplete(FluxSwitchIfEmpty.java:75)\r\n\t\tat reactor.core.publisher.MonoFlatMap$FlatMapMain.onComplete(MonoFlatMap.java:174)\r\n\t\tat reactor.core.publisher.MonoNext$NextSubscriber.onComplete(MonoNext.java:96)\r\n\t\tat reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.drain(FluxConcatMap.java:359)\r\n\t\tat reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.onSubscribe(FluxConcatMap.java:211)\r\n\t\tat reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:139)\r\n\t\tat reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:63)\r\n\t\tat reactor.core.publisher.Mono.subscribe(Mono.java:4105)\r\n\t\tat reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.drain(MonoIgnoreThen.java:172)\r\n\t\tat reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:56)\r\n\t\tat reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:150)\r\n\t\tat reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onNext(FluxSwitchIfEmpty.java:67)\r\n\t\tat reactor.core.publisher.MonoNext$NextSubscriber.onNext(MonoNext.java:76)\r\n\t\tat reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.innerNext(FluxConcatMap.java:274)\r\n\t\tat reactor.core.publisher.FluxConcatMap$ConcatMapInner.onNext(FluxConcatMap.java:851)\r\n\t\tat reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:121)\r\n\t\tat reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2199)\r\n\t\tat reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.request(FluxMapFuseable.java:162)\r\n\t\tat reactor.core.publisher.Operators$MultiSubscriptionSubscriber.set(Operators.java:2007)\r\n\t\tat reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onSubscribe(Operators.java:1881)\r\n\t\tat reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onSubscribe(FluxMapFuseable.java:90)\r\n\t\tat reactor.core.publisher.MonoJust.subscribe(MonoJust.java:54)\r\n\t\tat reactor.core.publisher.Mono.subscribe(Mono.java:4105)\r\n\t\tat reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.drain(FluxConcatMap.java:441)\r\n\t\tat reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.onSubscribe(FluxConcatMap.java:211)\r\n\t\tat reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:139)\r\n\t\tat reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:63)\r\n\t\tat reactor.core.publisher.Mono.subscribe(Mono.java:4105)\r\n\t\tat reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:97)\r\n\t\tat reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.onError(MonoPeekTerminal.java:251)\r\n\t\tat reactor.core.publisher.SerializedSubscriber.onError(SerializedSubscriber.java:114)\r\n\t\tat reactor.core.publisher.FluxTimeout$TimeoutMainSubscriber.handleTimeout(FluxTimeout.java:289)\r\n\t\tat reactor.core.publisher.FluxTimeout$TimeoutMainSubscriber.doTimeout(FluxTimeout.java:274)\r\n\t\tat reactor.core.publisher.FluxTimeout$TimeoutTimeoutSubscriber.onNext(FluxTimeout.java:396)\r\n\t\tat reactor.core.publisher.StrictSubscriber.onNext(StrictSubscriber.java:89)\r\n\t\tat reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:73)\r\n\t\tat reactor.core.publisher.MonoDelay$MonoDelayRunnable.run(MonoDelay.java:117)\r\n\t\tat reactor.core.scheduler.SchedulerTask.call(SchedulerTask.java:68)\r\n\t\tat reactor.core.scheduler.SchedulerTask.call(SchedulerTask.java:28)\r\n\t\tat java.util.concurrent.FutureTask.run(FutureTask.java:266)\r\n\t\tat java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)\r\n\t\tat java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)\r\n\t\tat java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)\r\n\t\tat java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)\r\n\t\tat java.lang.Thread.run(Thread.java:748)\r\n",
"success": "false",
"data": "",
"statusCode": "500"
}
Pom.xml
org.springframework.boot spring-boot-starter-parent 2.7.14 com.circuitbreaker servicea 0.0.1-SNAPSHOT ServiceA Spring Boot circuit breaker 1.8 2021.0.8 org.springframework.boot spring-boot-starter-aop org.springframework.boot spring-boot-starter-actuator org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-devtools runtime true org.springframework.cloud spring-cloud-starter-circuitbreaker-resilience4j com.sun.jersey.contribs jersey-apache-client4 1.19.4 org.springframework.cloud spring-cloud-starter-netflix-eureka-client org.springframework.cloud spring-cloud-dependencies ${spring-cloud.version} pom import org.springframework.boot spring-boot-maven-plugin
Java Code:-
@Autowired
RestTemplate restTemplate;
private static final String BASE_URL = "http://localhost:9007/b";
private static final String SERVICE_A = "servicea";
@GetMapping
@CIRCUITBREAKER(name = SERVICE_A, fallbackMethod = "serviceAFallback")
public String serviceA() {
return restTemplate.getForObject(BASE_URL, String.class);
}
public String serviceAFallback(Exception e) {
return "This is a fallback method for Service A";
}
Yaml File:-
resilience4j:
circuitbreaker:
instances:
servicea:
registerHealthIndicator: true
eventConsumerBufferSize: 10
failureRateThreshold: 50
minimumNumberOfCalls: 5
automaticTransitionFromOpenToHalfOpenEnabled: true
waitDurationInOpenState: 5s
permittedNumberOfCallsInHalfOpenState: 3
slidingWindowSize: 10
slidingWindowType: COUNT_BASED
I was excited to find your blog that appeared to defined custom circuit breakers for a given micro service instance.
However, following you property values I don't seem to be able to load what would be your custom backendB micro service properties. I always end up with the default configs?
The Registry upon entering the Factory bean has no circuit breaker:
log.debug("CIRCUIT BREAKER COUNT = " + circuitBreakerRegistry.getAllCircuitBreakers().asJava().size());
2021-11-08 08:23:56,766 DEBUG [restartedMain] com.me.gateway.config.GatewayCircuitBreakerConfig.reactiveResilience4JCircuitBreakerFactory:: CIRCUIT BREAKER COUNT = 0
What is not apparent is how the circuit breaker is tied to a route. My assumption was via the circuitBreaker attributes in the route:
.route(p -> p.path(PATH_PREFIX + CloudPath.AUTH_PATH.getPath() + ALL_SUBPATHS)
.filters(f
-> f.filters(filters)
.circuitBreaker(c -> c.setName(CloudPath.AUTH_PATH.getPath()).setFallbackUri(AUTH_SERVICE_FALLBACK_URI))
)
spring:
cloud:
circuitbreaker:
resliience4j:
enabled: true
resilience4j.circuitbreaker:
configs:
default:
slidingWindowSize: 10
minimumNumberOfCalls: 5
permittedNumberOfCallsInHalfOpenState: 3
automaticTransitionFromOpenToHalfOpenEnabled: true
waitDurationInOpenState: 2s
failureRateThreshold: 5
eventConsumerBufferSize: 10
slowCallDurationThreshold: 200ms
slowCallRateThreshold: 30
recordExceptions:
- org.springframework.web.client.HttpServerErrorException
- java.io.IOException
ignoreExceptions:
- java.lang.IllegalStateException
shared:
slidingWindowSize: 100
permittedNumberOfCallsInHalfOpenState: 30
waitDurationInOpenState: 1s
failureRateThreshold: 50
eventConsumerBufferSize: 10
ignoreExceptions:
- java.lang.IllegalStateException
instances:
auth-service:
slidingWindowSize: 1
minimumNumberOfCalls: 10
permittedNumberOfCallsInHalfOpenState: 3
waitDurationInOpenState: 1s
failureRateThreshold: 3
eventConsumerBufferSize: 1
resilience4j.timelimiter:
time-limiter-aspect-order: 398
configs:
default:
timeoutDuration: 1s
cancelRunningFuture: false
instances:
auth-service:
timeoutDuration: 250ms
raw code :
reactiveResilience4JCircuitBreakerFactory.configure( builder -> builder .timeLimiterConfig(timeLimiterRegistry.getConfiguration("backendB").orElse(TimeLimiterConfig.custom().timeoutDuration(Duration.ofMillis(300)).build())) .circuitBreakerConfig(circuitBreakerRegistry.getConfiguration("backendB").orElse(circuitBreakerRegistry.getDefaultConfig())), "backendB");
modified code :
reactiveResilience4JCircuitBreakerFactory.configure( builder -> builder .timeLimiterConfig(timeLimiterRegistry.getConfiguration("default").orElse(TimeLimiterConfig.custom().timeoutDuration(Duration.ofMillis(300)).build())) .circuitBreakerConfig(circuitBreakerRegistry.getConfiguration("default").orElse(circuitBreakerRegistry.getDefaultConfig())), "backendB");
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.