diff --git a/libraries.gradle b/libraries.gradle index f218499108..a20d8347ae 100644 --- a/libraries.gradle +++ b/libraries.gradle @@ -77,6 +77,7 @@ ext { // Micrometers addon micrometer: "io.micrometer:micrometer-core:${micrometerVersion}", + micrometer_prometheus: "io.micrometer:micrometer-registry-prometheus:${micrometerVersion}", // CircuitBreaker documentation metrics_healthcheck: "io.dropwizard.metrics:metrics-healthchecks:${metricsVersion}", diff --git a/resilience4j-documentation/src/docs/asciidoc/addon_guides/springboot2.adoc b/resilience4j-documentation/src/docs/asciidoc/addon_guides/springboot2.adoc new file mode 100644 index 0000000000..f7284a33cc --- /dev/null +++ b/resilience4j-documentation/src/docs/asciidoc/addon_guides/springboot2.adoc @@ -0,0 +1,310 @@ +=== Spring Boot Starter + +==== Gradle + +Add the Spring Boot 2 Starter of Resilience4j to your compile dependency: + +``` +repositories { + maven { url 'http://oss.jfrog.org/artifactory/oss-snapshot-local/' } + mavenCentral() +} + + +dependencies { + compile('io.github.resilience4j:resilience4j-spring-boot2:{release-version}') +} +``` + +==== Monitoring + +Spring Boot Actuator health information can be used to check the status of your running application. +It is often used by monitoring software to alert someone if a production system has serious issues. + +==== CircuitBreaker +This demo publishes the status and metrics of all CircuitBreakers via a custom `CircuitBreakerHealthIndicator`. +A closed CircuitBreaker state is mapped to UP, an open state to DOWN and a half-open state to UNKNOWN. + +For example: + +[source,json] +---- +{ + "status": "UP", + "backendACircuitBreaker": { + "status": "DOWN", + "failureRate": "60.0%", + "failureRateThreshold": "50.0%", + "maxBufferedCalls": 5, + "bufferedCalls": 5, + "failedCalls": 3, + "notPermittedCalls": 0 + }, + "backendBCircuitBreaker": { + "status": "UP", + "failureRate": "0.0%", + "failureRateThreshold": "50.0%", + "maxBufferedCalls": 10, + "bufferedCalls": 10, + "failedCalls": 0, + "notPermittedCalls": 0 + } +} +---- + +Metrics are automatically published on the Metrics endpoint. +For example: + +[source,json] +---- +{ + "names": [ + "resilience4j.circuitbreaker.backendA.successful", + "resilience4j.circuitbreaker.backendA.failed", + "resilience4j.circuitbreaker.backendA.buffered", + "resilience4j.circuitbreaker.backendA.buffered_max", + "resilience4j.circuitbreaker.backendA.not_permitted", + "resilience4j.circuitbreaker.backendB.successful", + "resilience4j.circuitbreaker.backendB.failed", + "resilience4j.circuitbreaker.backendB.buffered", + "resilience4j.circuitbreaker.backendB.buffered_max", + "resilience4j.circuitbreaker.backendB.not_permitted" + ] +} +---- + +When you want to publish CircuitBreaker endpoints on the Prometheus endpoint, you have to add the dependency `io.micrometer:micrometer-registry-prometheus`. +For example: + +[source] +---- +# HELP resilience4j_circuitbreaker_calls Circuit Breaker Call Stats +# TYPE resilience4j_circuitbreaker_calls gauge +resilience4j_circuitbreaker_calls{name="backendB",call_result="successful",} 0.0 +resilience4j_circuitbreaker_calls{name="backendB",call_result="failed",} 0.0 +resilience4j_circuitbreaker_calls{name="backendB",call_result="not_permitted",} 0.0 +resilience4j_circuitbreaker_calls{name="backendB",call_result="buffered",} 0.0 +resilience4j_circuitbreaker_calls{name="backendB",call_result="buffered_max",} 10.0 +resilience4j_circuitbreaker_calls{name="backendA",call_result="successful",} 0.0 +resilience4j_circuitbreaker_calls{name="backendA",call_result="failed",} 0.0 +resilience4j_circuitbreaker_calls{name="backendA",call_result="not_permitted",} 0.0 +resilience4j_circuitbreaker_calls{name="backendA",call_result="buffered",} 0.0 +resilience4j_circuitbreaker_calls{name="backendA",call_result="buffered_max",} 5.0 +# HELP resilience4j_circuitbreaker_states Circuit Breaker States +# TYPE resilience4j_circuitbreaker_states gauge +resilience4j_circuitbreaker_states{name="backendB",state="closed",} 1.0 +resilience4j_circuitbreaker_states{name="backendB",state="open",} 0.0 +resilience4j_circuitbreaker_states{name="backendB",state="half_open",} 0.0 +resilience4j_circuitbreaker_states{name="backendA",state="closed",} 1.0 +resilience4j_circuitbreaker_states{name="backendA",state="open",} 0.0 +resilience4j_circuitbreaker_states{name="backendA",state="half_open",} 0.0 +---- + +==== RateLimiter +This demo publishes the status and metrics of all RateLimiter via a custom `RateLimiterHealthIndicator`. +RateLimiterHealthIndicator changes its state DOWN only if there is some permission waiting threads +and they won't be able to unblock until timeout. + +For example: + +[source,json] +---- +{ + "status": "UP", + "backendARateLimiter": { + "status": "UP", + "availablePermissions": 10, + "numberOfWaitingThreads": 0 + } +} +---- + +Metrics are automatically published on the Metrics endpoint. +For example: + +[source,json] +---- +{ + "resilience4j.ratelimiter.backendA.available_permissions": 10, + "resilience4j.ratelimiter.backendA.number_of_waiting_threads": 0, + "resilience4j.ratelimiter.backendB.available_permissions": 6, + "resilience4j.ratelimiter.backendB.number_of_waiting_threads": 0 +} +---- + +==== Configuration + +===== CircuitBreaker +You can configure your CircuitBreakers in Spring Boot's `application.yml` config file. +For example + +[source,yaml] +---- +resilience4j.circuitbreaker: + backends: + backendA: + ringBufferSizeInClosedState: 5 + ringBufferSizeInHalfOpenState: 3 + waitInterval: 5000 + failureRateThreshold: 50 + eventConsumerBufferSize: 10 + registerHealthIndicator: true + backendB: + ringBufferSizeInClosedState: 10 + ringBufferSizeInHalfOpenState: 5 + waitInterval: 5000 + failureRateThreshold: 50 + eventConsumerBufferSize: 10 + registerHealthIndicator: true +---- + +===== RateLimiter +You can configure your CircuitBreakers in Spring Boot's `application.yml` config file. +For example + +[source,yaml] +---- +resilience4j.ratelimiter: + limiters: + backendA: + limitForPeriod: 10 + limitRefreshPeriodInMillis: 1000 + timeoutInMillis: 0 + subscribeForEvents: true + registerHealthIndicator: true + eventConsumerBufferSize: 100 + backendB: + limitForPeriod: 6 + limitRefreshPeriodInMillis: 500 + timeoutInMillis: 3000 +---- + +===== Explicit ordering for CircuitBreaker and RateLimiter aspects +You can adjust `RateLimiterProperties.rateLimiterAspectOrder` and `CircuitBreakerProperties.circuitBreakerAspectOrder` +and explicitly define `CircuitBreaker` and `RateLimiter` execution sequence. +By default `CircuitBreaker` will be executed BEFORE `RateLimiter`. + +WARNING: Please be careful changing of `CircuitBreaker`/`RateLimiter` ordering can drastically change application behavior. + +==== Event Monitoring + +===== CircuitBreaker + +The emitted CircuitBreaker events are stored in a separate circular event consumer buffers. The size of a event consumer buffer can be configured per CircuitBreaker in the application.yml file (eventConsumerBufferSize). +The demo adds a custom Spring Boot Actuator endpoint which can be used to monitor the emitted events of your CircuitBreakers. +The endpoint `/actuator/circuitbreakers` lists the names of all CircuitBreaker instances. +For example: + +---- +{ + "circuitBreakers": [ + "backendA", + "backendB" + ] +} +---- + +The endpoint `/management/circuitbreaker-events` lists the latest 100 emitted events of all CircuitBreaker instances. + +---- +{ +"circuitBreakerEvents":[ + { + "circuitBreakerName": "backendA", + "type": "ERROR", + "creationTime": "2017-01-10T15:39:17.117+01:00[Europe/Berlin]", + "errorMessage": "org.springframework.web.client.HttpServerErrorException: 500 This is a remote exception", + "durationInMs": 0 + }, + { + "circuitBreakerName": "backendA", + "type": "SUCCESS", + "creationTime": "2017-01-10T15:39:20.518+01:00[Europe/Berlin]", + "durationInMs": 0 + }, + { + "circuitBreakerName": "backendB", + "type": "ERROR", + "creationTime": "2017-01-10T15:41:31.159+01:00[Europe/Berlin]", + "errorMessage": "org.springframework.web.client.HttpServerErrorException: 500 This is a remote exception", + "durationInMs": 0 + }, + { + "circuitBreakerName": "backendB", + "type": "SUCCESS", + "creationTime": "2017-01-10T15:41:33.526+01:00[Europe/Berlin]", + "durationInMs": 0 + } +] +} +---- + +The endpoint `/management/circuitbreaker/events/{circuitBreakerName}` lists the latest emitted events of a specific CircuitBreaker. +For example `/management/circuitbreaker/events/backendA`: + +---- +{ +"circuitBreakerEvents":[ + { + "circuitBreakerName": "backendA", + "type": "ERROR", + "creationTime": "2017-01-10T15:39:17.117+01:00[Europe/Berlin]", + "errorMessage": "org.springframework.web.client.HttpServerErrorException: 500 This is a remote exception", + "durationInMs": 0 + }, + { + "circuitBreakerName": "backendA", + "type": "SUCCESS", + "creationTime": "2017-01-10T15:39:20.518+01:00[Europe/Berlin]", + "durationInMs": 0 + }, + { + "circuitBreakerName": "backendA", + "type": "STATE_TRANSITION", + "creationTime": "2017-01-10T15:39:22.341+01:00[Europe/Berlin]", + "stateTransition": "CLOSED_TO_OPEN" + }, + { + "circuitBreakerName": "backendA", + "type": "NOT_PERMITTED", + "creationTime": "2017-01-10T15:39:22.780+01:00[Europe/Berlin]" + } +] +} +---- + +===== RateLimiter +WARNING: Unlike the CircuitBreaker events, RateLimiter events require explicit subscription. +Use property resilience4j.ratelimiter.limiters.{yourBackendName}.registerHealthIndicator=true + +There are literally the same endpoints implemented for RateLimiter, +so for detailed documentation please refer to previous section: + +List of available endpoints: + +* `/ratelimiters` +* `/ratelimiter-events` +* `/ratelimiter-events/{rateLimiterName}` + +Example of response: +---- +{ + "eventsList": [ + { + "rateLimiterName": "backendA", + "rateLimiterEventType": "SUCCESSFUL_ACQUIRE", + "rateLimiterCreationTime": "2017-05-05T21:29:40.463+03:00[Europe/Uzhgorod]" + }, + { + "rateLimiterName": "backendA", + "rateLimiterEventType": "SUCCESSFUL_ACQUIRE", + "rateLimiterCreationTime": "2017-05-05T21:29:40.469+03:00[Europe/Uzhgorod]" + }, + { + "rateLimiterName": "backendA", + "rateLimiterEventType": "FAILED_ACQUIRE", + "rateLimiterCreationTime": "2017-05-05T21:29:41.268+03:00[Europe/Uzhgorod]" + } + ] +} +---- diff --git a/resilience4j-spring-boot2/build.gradle b/resilience4j-spring-boot2/build.gradle index 58f719a88c..9faf9a1c11 100644 --- a/resilience4j-spring-boot2/build.gradle +++ b/resilience4j-spring-boot2/build.gradle @@ -6,5 +6,6 @@ dependencies { compile project(':resilience4j-ratelimiter') compile project(':resilience4j-consumer') testCompile ( libraries.spring_boot2_test ) + testCompile ( libraries.micrometer_prometheus ) testCompile ( libraries.spring_boot2_web ) } \ No newline at end of file diff --git a/resilience4j-spring-boot2/src/main/java/io/github/resilience4j/circuitbreaker/autoconfigure/CircuitBreakerAutoConfiguration.java b/resilience4j-spring-boot2/src/main/java/io/github/resilience4j/circuitbreaker/autoconfigure/CircuitBreakerAutoConfiguration.java index c17a0d82a7..f827d302b9 100644 --- a/resilience4j-spring-boot2/src/main/java/io/github/resilience4j/circuitbreaker/autoconfigure/CircuitBreakerAutoConfiguration.java +++ b/resilience4j-spring-boot2/src/main/java/io/github/resilience4j/circuitbreaker/autoconfigure/CircuitBreakerAutoConfiguration.java @@ -73,9 +73,8 @@ public CircuitBreakerEndpoint circuitBreakerEndpoint(CircuitBreakerRegistry circ @Bean @ConditionalOnEnabledEndpoint - public CircuitBreakerEventsEndpoint circuitBreakerEventsEndpoint(EventConsumerRegistry eventConsumerRegistry, - CircuitBreakerRegistry circuitBreakerRegistry) { - return new CircuitBreakerEventsEndpoint(eventConsumerRegistry, circuitBreakerRegistry); + public CircuitBreakerEventsEndpoint circuitBreakerEventsEndpoint(EventConsumerRegistry eventConsumerRegistry) { + return new CircuitBreakerEventsEndpoint(eventConsumerRegistry); } @Bean diff --git a/resilience4j-spring-boot2/src/main/java/io/github/resilience4j/circuitbreaker/monitoring/endpoint/CircuitBreakerEndpoint.java b/resilience4j-spring-boot2/src/main/java/io/github/resilience4j/circuitbreaker/monitoring/endpoint/CircuitBreakerEndpoint.java index 37b3467176..611dd1ce6d 100644 --- a/resilience4j-spring-boot2/src/main/java/io/github/resilience4j/circuitbreaker/monitoring/endpoint/CircuitBreakerEndpoint.java +++ b/resilience4j-spring-boot2/src/main/java/io/github/resilience4j/circuitbreaker/monitoring/endpoint/CircuitBreakerEndpoint.java @@ -18,14 +18,14 @@ import java.util.List; +import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; -import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpoint; import io.github.resilience4j.circuitbreaker.CircuitBreaker; import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry; -@WebEndpoint(id = "circuitbreaker") +@Endpoint(id = "circuitbreakers") public class CircuitBreakerEndpoint { private final CircuitBreakerRegistry circuitBreakerRegistry; diff --git a/resilience4j-spring-boot2/src/main/java/io/github/resilience4j/circuitbreaker/monitoring/endpoint/CircuitBreakerEventsEndpoint.java b/resilience4j-spring-boot2/src/main/java/io/github/resilience4j/circuitbreaker/monitoring/endpoint/CircuitBreakerEventsEndpoint.java index 08d55aedae..ed25f663e3 100644 --- a/resilience4j-spring-boot2/src/main/java/io/github/resilience4j/circuitbreaker/monitoring/endpoint/CircuitBreakerEventsEndpoint.java +++ b/resilience4j-spring-boot2/src/main/java/io/github/resilience4j/circuitbreaker/monitoring/endpoint/CircuitBreakerEventsEndpoint.java @@ -18,27 +18,22 @@ import java.util.Comparator; +import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; import org.springframework.boot.actuate.endpoint.annotation.Selector; -import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpoint; -import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry; import io.github.resilience4j.circuitbreaker.event.CircuitBreakerEvent; import io.github.resilience4j.consumer.CircularEventConsumer; import io.github.resilience4j.consumer.EventConsumerRegistry; -@WebEndpoint(id = "circuitbreaker-events") +@Endpoint(id = "circuitbreaker-events") public class CircuitBreakerEventsEndpoint { - private static final String MEDIA_TYPE_TEXT_EVENT_STREAM = "text/event-stream"; private final EventConsumerRegistry eventConsumerRegistry; - private final CircuitBreakerRegistry circuitBreakerRegistry; - public CircuitBreakerEventsEndpoint(EventConsumerRegistry eventConsumerRegistry, - CircuitBreakerRegistry circuitBreakerRegistry) { + public CircuitBreakerEventsEndpoint(EventConsumerRegistry eventConsumerRegistry) { this.eventConsumerRegistry = eventConsumerRegistry; - this.circuitBreakerRegistry = circuitBreakerRegistry; } @ReadOperation @@ -50,19 +45,9 @@ public CircuitBreakerEventsEndpointResponse getAllCircuitBreakerEvents() { } @ReadOperation - public CircuitBreakerEventsEndpointResponse getEventsFilteredByCircuitBreakerName(@Selector String circuitBreakerName) { - return new CircuitBreakerEventsEndpointResponse(eventConsumerRegistry.getEventConsumer(circuitBreakerName).getBufferedEvents() - .filter(event -> event.getCircuitBreakerName().equals(circuitBreakerName)) + public CircuitBreakerEventsEndpointResponse getEventsFilteredByCircuitBreakerName(@Selector String name) { + return new CircuitBreakerEventsEndpointResponse(eventConsumerRegistry.getEventConsumer(name).getBufferedEvents() + .filter(event -> event.getCircuitBreakerName().equals(name)) .map(CircuitBreakerEventDTOFactory::createCircuitBreakerEventDTO).toJavaList()); } - - @ReadOperation - public CircuitBreakerEventsEndpointResponse getEventsFilteredByCircuitBreakerNameAndEventType(@Selector String circuitBreakerName, - @Selector String eventType) { - return new CircuitBreakerEventsEndpointResponse(eventConsumerRegistry.getEventConsumer(circuitBreakerName).getBufferedEvents() - .filter(event -> event.getCircuitBreakerName().equals(circuitBreakerName)) - .filter(event -> event.getEventType() == CircuitBreakerEvent.Type.valueOf(eventType.toUpperCase())) - .map(CircuitBreakerEventDTOFactory::createCircuitBreakerEventDTO).toJavaList()); - } - } diff --git a/resilience4j-spring-boot2/src/main/java/io/github/resilience4j/ratelimiter/autoconfigure/RateLimiterAutoConfiguration.java b/resilience4j-spring-boot2/src/main/java/io/github/resilience4j/ratelimiter/autoconfigure/RateLimiterAutoConfiguration.java index e56dc20aa1..5f6afb508b 100644 --- a/resilience4j-spring-boot2/src/main/java/io/github/resilience4j/ratelimiter/autoconfigure/RateLimiterAutoConfiguration.java +++ b/resilience4j-spring-boot2/src/main/java/io/github/resilience4j/ratelimiter/autoconfigure/RateLimiterAutoConfiguration.java @@ -76,9 +76,8 @@ public RateLimiterEndpoint rateLimiterEndpoint(RateLimiterRegistry rateLimiterRe @Bean @ConditionalOnEnabledEndpoint - public RateLimiterEventsEndpoint rateLimiterEventsEndpoint(EventConsumerRegistry eventConsumerRegistry, - RateLimiterRegistry rateLimiterRegistry) { - return new RateLimiterEventsEndpoint(eventConsumerRegistry, rateLimiterRegistry); + public RateLimiterEventsEndpoint rateLimiterEventsEndpoint(EventConsumerRegistry eventConsumerRegistry) { + return new RateLimiterEventsEndpoint(eventConsumerRegistry); } @Bean diff --git a/resilience4j-spring-boot2/src/main/java/io/github/resilience4j/ratelimiter/monitoring/endpoint/RateLimiterEndpoint.java b/resilience4j-spring-boot2/src/main/java/io/github/resilience4j/ratelimiter/monitoring/endpoint/RateLimiterEndpoint.java index 49dccac837..260a9ccaee 100644 --- a/resilience4j-spring-boot2/src/main/java/io/github/resilience4j/ratelimiter/monitoring/endpoint/RateLimiterEndpoint.java +++ b/resilience4j-spring-boot2/src/main/java/io/github/resilience4j/ratelimiter/monitoring/endpoint/RateLimiterEndpoint.java @@ -17,14 +17,14 @@ import java.util.List; +import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; -import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpoint; import io.github.resilience4j.ratelimiter.RateLimiter; import io.github.resilience4j.ratelimiter.RateLimiterRegistry; import io.github.resilience4j.ratelimiter.monitoring.model.RateLimiterEndpointResponse; -@WebEndpoint(id = "ratelimiter") +@Endpoint(id = "ratelimiters") public class RateLimiterEndpoint { private final RateLimiterRegistry rateLimiterRegistry; diff --git a/resilience4j-spring-boot2/src/main/java/io/github/resilience4j/ratelimiter/monitoring/endpoint/RateLimiterEventsEndpoint.java b/resilience4j-spring-boot2/src/main/java/io/github/resilience4j/ratelimiter/monitoring/endpoint/RateLimiterEventsEndpoint.java index 3bbc1ca9ad..eede4a5e53 100644 --- a/resilience4j-spring-boot2/src/main/java/io/github/resilience4j/ratelimiter/monitoring/endpoint/RateLimiterEventsEndpoint.java +++ b/resilience4j-spring-boot2/src/main/java/io/github/resilience4j/ratelimiter/monitoring/endpoint/RateLimiterEventsEndpoint.java @@ -24,21 +24,16 @@ import io.github.resilience4j.consumer.CircularEventConsumer; import io.github.resilience4j.consumer.EventConsumerRegistry; -import io.github.resilience4j.ratelimiter.RateLimiterRegistry; import io.github.resilience4j.ratelimiter.event.RateLimiterEvent; import io.github.resilience4j.ratelimiter.monitoring.model.RateLimiterEventDTO; import io.github.resilience4j.ratelimiter.monitoring.model.RateLimiterEventsEndpointResponse; @Endpoint(id = "ratelimiter-events") public class RateLimiterEventsEndpoint { - private static final String MEDIA_TYPE_TEXT_EVENT_STREAM = "text/event-stream"; private final EventConsumerRegistry eventsConsumerRegistry; - private final RateLimiterRegistry rateLimiterRegistry; - public RateLimiterEventsEndpoint(EventConsumerRegistry eventsConsumerRegistry, - RateLimiterRegistry rateLimiterRegistry) { + public RateLimiterEventsEndpoint(EventConsumerRegistry eventsConsumerRegistry) { this.eventsConsumerRegistry = eventsConsumerRegistry; - this.rateLimiterRegistry = rateLimiterRegistry; } @ReadOperation @@ -57,15 +52,4 @@ public RateLimiterEventsEndpointResponse getEventsFilteredByRateLimiterName(@Sel .map(RateLimiterEventDTO::createRateLimiterEventDTO).toJavaList(); return new RateLimiterEventsEndpointResponse(eventsList); } - - @ReadOperation - public RateLimiterEventsEndpointResponse getEventsFilteredByRateLimiterNameAndEventType(@Selector String rateLimiterName, - @Selector String eventType) { - RateLimiterEvent.Type targetType = RateLimiterEvent.Type.valueOf(eventType.toUpperCase()); - List eventsList = eventsConsumerRegistry.getEventConsumer(rateLimiterName).getBufferedEvents() - .filter(event -> event.getRateLimiterName().equals(rateLimiterName)) - .filter(event -> event.getEventType() == targetType) - .map(RateLimiterEventDTO::createRateLimiterEventDTO).toJavaList(); - return new RateLimiterEventsEndpointResponse(eventsList); - } } diff --git a/resilience4j-spring-boot2/src/test/java/io/github/resilience4j/circuitbreaker/CircuitBreakerAutoConfigurationTest.java b/resilience4j-spring-boot2/src/test/java/io/github/resilience4j/circuitbreaker/CircuitBreakerAutoConfigurationTest.java index 3c53d3c2c0..bf990fbd0c 100644 --- a/resilience4j-spring-boot2/src/test/java/io/github/resilience4j/circuitbreaker/CircuitBreakerAutoConfigurationTest.java +++ b/resilience4j-spring-boot2/src/test/java/io/github/resilience4j/circuitbreaker/CircuitBreakerAutoConfigurationTest.java @@ -84,13 +84,18 @@ public void testCircuitBreakerAutoConfiguration() throws IOException { // Test Actuator endpoints - ResponseEntity circuitBreakerList = restTemplate.getForEntity("/actuator/circuitbreaker", CircuitBreakerEndpointResponse.class); + ResponseEntity circuitBreakerList = restTemplate.getForEntity("/actuator/circuitbreakers", CircuitBreakerEndpointResponse.class); assertThat(circuitBreakerList.getBody().getCircuitBreakers()).hasSize(2).containsExactly("backendA", "backendB"); ResponseEntity circuitBreakerEventList = restTemplate.getForEntity("/actuator/circuitbreaker-events", CircuitBreakerEventsEndpointResponse.class); assertThat(circuitBreakerEventList.getBody().getCircuitBreakerEvents()).hasSize(2); + circuitBreakerEventList = restTemplate.getForEntity("/actuator/circuitbreaker-events?name=backendA", CircuitBreakerEventsEndpointResponse.class); + assertThat(circuitBreakerEventList.getBody().getCircuitBreakerEvents()).hasSize(2); + + + assertThat(circuitBreakerAspect.getOrder()).isEqualTo(400); } } diff --git a/resilience4j-spring-boot2/src/test/java/io/github/resilience4j/ratelimiter/RateLimiterAutoConfigurationTest.java b/resilience4j-spring-boot2/src/test/java/io/github/resilience4j/ratelimiter/RateLimiterAutoConfigurationTest.java index 60857aa666..cd5a54bc52 100644 --- a/resilience4j-spring-boot2/src/test/java/io/github/resilience4j/ratelimiter/RateLimiterAutoConfigurationTest.java +++ b/resilience4j-spring-boot2/src/test/java/io/github/resilience4j/ratelimiter/RateLimiterAutoConfigurationTest.java @@ -93,7 +93,7 @@ public void testRateLimiterAutoConfiguration() throws IOException { // Test Actuator endpoints ResponseEntity rateLimiterList = restTemplate - .getForEntity("/actuator/ratelimiter", RateLimiterEndpointResponse.class); + .getForEntity("/actuator/ratelimiters", RateLimiterEndpointResponse.class); assertThat(rateLimiterList.getBody().getRateLimitersNames()).hasSize(2).containsExactly("backendA", "backendB"); diff --git a/resilience4j-spring-boot2/src/test/resources/application.yaml b/resilience4j-spring-boot2/src/test/resources/application.yaml index f344e13099..bb33148313 100644 --- a/resilience4j-spring-boot2/src/test/resources/application.yaml +++ b/resilience4j-spring-boot2/src/test/resources/application.yaml @@ -2,6 +2,7 @@ resilience4j.circuitbreaker: circuitBreakerAspectOrder: 400 backends: backendA: + registerHealthIndicator: true ringBufferSizeInClosedState: 6 ringBufferSizeInHalfOpenState: 2 waitInterval: 5000 @@ -9,6 +10,7 @@ resilience4j.circuitbreaker: eventConsumerBufferSize: 10 registerHealthIndicator: true backendB: + registerHealthIndicator: true ringBufferSizeInClosedState: 10 ringBufferSizeInHalfOpenState: 5 waitInterval: 5000 @@ -31,4 +33,5 @@ resilience4j.ratelimiter: timeoutInMillis: 3000 management.security.enabled: false -management.endpoints.web.exposure.include: '*' \ No newline at end of file +management.endpoints.web.exposure.include: '*' +management.endpoint.health.show-details: always \ No newline at end of file