assertThat(circuitBreaker).isNotNull(); assertThat(circuitBreaker.getMetrics().getNumberOfBufferedCalls()).isEqualTo(2); assertThat(circuitBreaker.getMetrics().getNumberOfSuccessfulCalls()).isEqualTo(1); assertThat(circuitBreaker.getMetrics().getNumberOfFailedCalls()).isEqualTo(1);
metrics.getNumberOfSuccessfulCalls()); metrics.getNumberOfFailedCalls()); metrics.getNumberOfNotPermittedCalls()); metrics.getNumberOfBufferedCalls()); metrics.getMaxNumberOfBufferedCalls());
private CircuitBreakerMetrics(String prefix, Iterable<CircuitBreaker> circuitBreakers) { requireNonNull(prefix); requireNonNull(circuitBreakers); circuitBreakers.forEach((CircuitBreaker circuitBreaker) -> { String name = circuitBreaker.getName(); //state as an integer metricRegistry.register(name(prefix, name, STATE), (Gauge<Integer>)()-> circuitBreaker.getState().getOrder()); metricRegistry.register(name(prefix, name, SUCCESSFUL), (Gauge<Integer>) () -> circuitBreaker.getMetrics().getNumberOfSuccessfulCalls()); metricRegistry.register(name(prefix, name, FAILED), (Gauge<Integer>) () -> circuitBreaker.getMetrics().getNumberOfFailedCalls()); metricRegistry.register(name(prefix, name, NOT_PERMITTED), (Gauge<Long>) () -> circuitBreaker.getMetrics().getNumberOfNotPermittedCalls()); metricRegistry.register(name(prefix, name, BUFFERED), (Gauge<Integer>) () -> circuitBreaker.getMetrics().getNumberOfBufferedCalls()); metricRegistry.register(name(prefix, name, BUFFERED_MAX), (Gauge<Integer>) () -> circuitBreaker.getMetrics().getMaxNumberOfBufferedCalls()); } ); }
assertThat(circuitBreaker.getMetrics().getNumberOfBufferedCalls()).isEqualTo(5); assertThat(circuitBreaker.getMetrics().getNumberOfFailedCalls()).isEqualTo(3); assertThat(circuitBreaker.getMetrics().getFailureRate()).isEqualTo(60.0f); assertCircuitBreakerMetricsEqualTo(60.0f, null, 5, null, 3, 0L); assertThat(circuitBreaker.isCallPermitted()).isEqualTo(false); // Should create a CircuitBreakerOnCallNotPermittedEvent (8) assertThat(circuitBreaker.getMetrics().getNumberOfNotPermittedCalls()).isEqualTo(2); assertThat(circuitBreaker.getMetrics().getNumberOfFailedCalls()).isEqualTo(0); assertCircuitBreakerMetricsEqualTo(-1f, null, 0, 3, 0, 0L); assertThat(circuitBreaker.getMetrics().getNumberOfBufferedCalls()).isEqualTo(3); assertThat(circuitBreaker.getMetrics().getNumberOfFailedCalls()).isEqualTo(2); assertThat(circuitBreaker.getMetrics().getFailureRate()).isGreaterThan(50f);
this.assertAllGroupACircuitBreakers((CircuitBreaker cb) -> cb.getMetrics().getNumberOfBufferedCalls(), 5); this.assertAllGroupACircuitBreakers((CircuitBreaker cb) -> cb.getMetrics().getNumberOfFailedCalls(), 3); this.assertAllGroupACircuitBreakers((CircuitBreaker cb) -> cb.getMetrics().getFailureRate(), 60.0f); this.assertAllGroupAMetricsEqualTo(60.0f, null, 5, null, 3, 0L); this.assertAllGroupBCircuitBreakers((CircuitBreaker cb) -> cb.getMetrics().getNumberOfBufferedCalls(), 5); this.assertAllGroupBCircuitBreakers((CircuitBreaker cb) -> cb.getMetrics().getNumberOfFailedCalls(), 3); this.assertAllGroupBCircuitBreakers((CircuitBreaker cb) -> cb.getMetrics().getFailureRate(), 60.0f); this.assertAllGroupBMetricsEqualTo(60.0f, null, 5, null, 3, 0L); this.assertAllGroupACircuitBreakers(CircuitBreaker::isCallPermitted, false); // Should create a CircuitBreakerOnCallNotPermittedEvent (8) this.assertAllGroupACircuitBreakers((CircuitBreaker cb) -> cb.getMetrics().getNumberOfNotPermittedCalls(), 2L); this.assertAllGroupBCircuitBreakers(CircuitBreaker::isCallPermitted, false); // Should create a CircuitBreakerOnCallNotPermittedEvent (8) this.assertAllGroupBCircuitBreakers((CircuitBreaker cb) -> cb.getMetrics().getNumberOfNotPermittedCalls(), 2L); this.assertAllGroupACircuitBreakers(CircuitBreaker::isCallPermitted, false); // Should create a CircuitBreakerOnCallNotPermittedEvent (10) this.assertAllGroupACircuitBreakers((CircuitBreaker cb) -> cb.getMetrics().getNumberOfNotPermittedCalls(), 4L); this.assertAllGroupBCircuitBreakers((CircuitBreaker cb) -> cb.getMetrics().getNumberOfFailedCalls(), 0); this.assertAllGroupBMetricsEqualTo(-1f, null, 0, 3, 0, 0L); this.assertAllGroupACircuitBreakers((CircuitBreaker cb) -> cb.getMetrics().getNumberOfFailedCalls(), 0); this.assertAllGroupAMetricsEqualTo(-1f, null, 0, 3, 0, 0L);
assertThat(circuitBreaker.getMetrics().getNumberOfBufferedCalls(), equalTo(0)); assertThat(circuitBreaker.getMetrics().getNumberOfFailedCalls(), equalTo(0)); assertThat(circuitBreaker.getMetrics().getNumberOfSuccessfulCalls(), equalTo(0)); assertThat(gauges.get("resilience4j.circuitbreaker.test.state").getValue(), equalTo(0)); assertThat(gauges.get("resilience4j.circuitbreaker.test.buffered").getValue(), equalTo(0)); assertThat(circuitBreaker.getMetrics().getNumberOfBufferedCalls(), equalTo(1)); assertThat(circuitBreaker.getMetrics().getNumberOfFailedCalls(), equalTo(1)); assertThat(circuitBreaker.getMetrics().getNumberOfSuccessfulCalls(), equalTo(0)); assertThat(gauges.get("resilience4j.circuitbreaker.test.state").getValue(), equalTo(0)); assertThat(gauges.get("resilience4j.circuitbreaker.test.buffered").getValue(), equalTo(1)); assertThat(circuitBreaker.getMetrics().getNumberOfBufferedCalls(), equalTo(10)); assertThat(circuitBreaker.getMetrics().getNumberOfFailedCalls(), equalTo(10)); assertThat(circuitBreaker.getMetrics().getNumberOfSuccessfulCalls(), equalTo(0)); assertThat(gauges.get("resilience4j.circuitbreaker.test.state").getValue(), equalTo(1)); assertThat(gauges.get("resilience4j.circuitbreaker.test.buffered").getValue(), equalTo(10)); assertThat(circuitBreaker.getMetrics().getNumberOfBufferedCalls(), equalTo(1)); assertThat(circuitBreaker.getMetrics().getNumberOfFailedCalls(), equalTo(0)); assertThat(circuitBreaker.getMetrics().getNumberOfSuccessfulCalls(), equalTo(1)); circuitBreaker.onSuccess(0); assertThat(circuitBreaker.getState(), equalTo(CircuitBreaker.State.HALF_OPEN)); assertThat(circuitBreaker.getMetrics().getNumberOfBufferedCalls(), equalTo(2)); assertThat(circuitBreaker.getMetrics().getNumberOfFailedCalls(), equalTo(0)); assertThat(circuitBreaker.getMetrics().getNumberOfSuccessfulCalls(), equalTo(2)); circuitBreaker.onSuccess(0);
when(metrics.getFailureRate()).thenReturn(0.2f); when(metrics.getMaxNumberOfBufferedCalls()).thenReturn(100); when(metrics.getNumberOfBufferedCalls()).thenReturn(100); when(metrics.getNumberOfFailedCalls()).thenReturn(20); when(metrics.getNumberOfNotPermittedCalls()).thenReturn(0L);
assertThat(metrics.getNumberOfFailedCalls()) .describedAs("Failed calls") .isEqualTo(1); assertThat(metrics.getNumberOfFailedCalls()) .isEqualTo(3);
assertThat(circuitBreaker).isNotNull(); assertThat(circuitBreaker.getMetrics().getNumberOfBufferedCalls()).isEqualTo(2); assertThat(circuitBreaker.getMetrics().getNumberOfSuccessfulCalls()).isEqualTo(1); assertThat(circuitBreaker.getMetrics().getNumberOfFailedCalls()).isEqualTo(1);
assertThat(metrics.getNumberOfBufferedCalls()).isEqualTo(1); assertThat(metrics.getNumberOfFailedCalls()).isEqualTo(1);
when(metrics.getFailureRate()).thenReturn(0.2f); when(metrics.getMaxNumberOfBufferedCalls()).thenReturn(100); when(metrics.getNumberOfBufferedCalls()).thenReturn(100); when(metrics.getNumberOfFailedCalls()).thenReturn(20); when(metrics.getNumberOfNotPermittedCalls()).thenReturn(0L);
assertThat(metrics.getNumberOfBufferedCalls()).isEqualTo(3); assertThat(metrics.getNumberOfFailedCalls()).isEqualTo(2); assertThat(resetMetrics.getNumberOfBufferedCalls()).isEqualTo(0); assertThat(resetMetrics.getNumberOfFailedCalls()).isEqualTo(0);
assertThat(metrics.getNumberOfFailedCalls()) .describedAs("Failed calls") .isEqualTo(1); assertThat(metrics.getNumberOfFailedCalls()) .isEqualTo(3);
@Test public void shouldThrowCircuitBreakerOpenException() { // tag::shouldThrowCircuitBreakerOpenException[] // Given CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom() .ringBufferSizeInClosedState(2) .waitDurationInOpenState(Duration.ofMillis(1000)) .build(); CircuitBreaker circuitBreaker = CircuitBreaker.of("testName", circuitBreakerConfig); // Simulate a failure attempt circuitBreaker.onError(0, new RuntimeException()); // CircuitBreaker is still CLOSED, because 1 failure is allowed assertThat(circuitBreaker.getState()).isEqualTo(CircuitBreaker.State.CLOSED); // Simulate a failure attempt circuitBreaker.onError(0, new RuntimeException()); // CircuitBreaker is OPEN, because the failure rate is above 50% assertThat(circuitBreaker.getState()).isEqualTo(CircuitBreaker.State.OPEN); // When I decorate my function and invoke the decorated function Try<String> result = Try.of(CircuitBreaker.decorateCheckedSupplier(circuitBreaker, () -> "Hello")) .map(value -> value + " world"); // Then the call fails, because CircuitBreaker is OPEN assertThat(result.isFailure()).isTrue(); // Exception is CircuitBreakerOpenException assertThat(result.failed().get()).isInstanceOf(CircuitBreakerOpenException.class); // end::shouldThrowCircuitBreakerOpenException[] CircuitBreaker.Metrics metrics = circuitBreaker.getMetrics(); assertThat(metrics.getNumberOfBufferedCalls()).isEqualTo(2); assertThat(metrics.getNumberOfFailedCalls()).isEqualTo(2); }
private void assertCircuitBreakerMetricsEqualTo(List<CircuitBreaker> circuitBreakers, Float expectedFailureRate, Integer expectedSuccessCalls, Integer expectedBufferedCalls, Integer expectedMaxBufferedCalls, Integer expectedFailedCalls, Long expectedNotPermittedCalls) { circuitBreakers.forEach(circuitBreaker -> { final CircuitBreaker.Metrics metrics = circuitBreaker.getMetrics(); if (expectedFailureRate != null) { assertThat(metrics.getFailureRate()).isEqualTo(expectedFailureRate); } if (expectedSuccessCalls != null) { assertThat(metrics.getNumberOfSuccessfulCalls()).isEqualTo(expectedSuccessCalls); } if (expectedBufferedCalls != null) { assertThat(metrics.getNumberOfBufferedCalls()).isEqualTo(expectedBufferedCalls); } if (expectedMaxBufferedCalls != null) { assertThat(metrics.getMaxNumberOfBufferedCalls()).isEqualTo(expectedMaxBufferedCalls); } if (expectedFailedCalls != null) { assertThat(metrics.getNumberOfFailedCalls()).isEqualTo(expectedFailedCalls); } if (expectedNotPermittedCalls != null) { assertThat(metrics.getNumberOfNotPermittedCalls()).isEqualTo(expectedNotPermittedCalls); } }); }
assertThat(circuitBreaker.getState()).isEqualTo(CircuitBreaker.State.OPEN); CircuitBreaker.Metrics metrics = circuitBreaker.getMetrics(); assertThat(metrics.getNumberOfBufferedCalls()).isEqualTo(2); assertThat(metrics.getNumberOfFailedCalls()).isEqualTo(2); assertThat(metrics.getNumberOfBufferedCalls()).isEqualTo(2); assertThat(metrics.getNumberOfFailedCalls()).isEqualTo(2); assertThat(metrics.getNumberOfNotPermittedCalls()).isEqualTo(1);
@Test public void shouldReturnFailureWithCircuitBreakerOpenException() { // Given // Create a custom configuration for a CircuitBreaker CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom() .ringBufferSizeInClosedState(2) .ringBufferSizeInHalfOpenState(2) .failureRateThreshold(50) .waitDurationInOpenState(Duration.ofMillis(1000)) .build(); // Create a CircuitBreakerRegistry with a custom global configuration CircuitBreaker circuitBreaker = CircuitBreaker.of("testName", circuitBreakerConfig); circuitBreaker.onError(0, new RuntimeException()); circuitBreaker.onError(0, new RuntimeException()); assertThat(circuitBreaker.getState()).isEqualTo(CircuitBreaker.State.OPEN); CircuitBreaker.Metrics metrics = circuitBreaker.getMetrics(); assertThat(metrics.getNumberOfBufferedCalls()).isEqualTo(2); assertThat(metrics.getNumberOfFailedCalls()).isEqualTo(2); //When CheckedRunnable checkedRunnable = CircuitBreaker.decorateCheckedRunnable(circuitBreaker, () -> { throw new RuntimeException("BAM!"); }); Try result = Try.run(checkedRunnable); //Then assertThat(result.isFailure()).isTrue(); assertThat(result.failed().get()).isInstanceOf(CircuitBreakerOpenException.class); }
@Test public void shouldChainDecoratedFunctions() throws ExecutionException, InterruptedException { // tag::shouldChainDecoratedFunctions[] // Given CircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults("testName"); CircuitBreaker anotherCircuitBreaker = CircuitBreaker.ofDefaults("anotherTestName"); // When I create a Supplier and a Function which are decorated by different CircuitBreakers CheckedFunction0<String> decoratedSupplier = CircuitBreaker .decorateCheckedSupplier(circuitBreaker, () -> "Hello"); CheckedFunction1<String, String> decoratedFunction = CircuitBreaker .decorateCheckedFunction(anotherCircuitBreaker, (input) -> input + " world"); // and I chain a function with map Try<String> result = Try.of(decoratedSupplier) .mapTry(decoratedFunction::apply); // Then assertThat(result.isSuccess()).isTrue(); assertThat(result.get()).isEqualTo("Hello world"); // end::shouldChainDecoratedFunctions[] CircuitBreaker.Metrics metrics = circuitBreaker.getMetrics(); assertThat(metrics.getNumberOfBufferedCalls()).isEqualTo(1); assertThat(metrics.getNumberOfFailedCalls()).isEqualTo(0); metrics = anotherCircuitBreaker.getMetrics(); assertThat(metrics.getNumberOfBufferedCalls()).isEqualTo(1); assertThat(metrics.getNumberOfFailedCalls()).isEqualTo(0); }
@Test public void shouldDecorateCompletionStageAndReturnWithSuccess() throws ExecutionException, InterruptedException { // Given CircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults("backendName"); assertThat(circuitBreaker.getState()).isEqualTo(CircuitBreaker.State.CLOSED); // Given the HelloWorldService returns Hello world BDDMockito.given(helloWorldService.returnHelloWorld()).willReturn("Hello"); // When Supplier<CompletionStage<String>> completionStageSupplier = () -> CompletableFuture.supplyAsync(helloWorldService::returnHelloWorld); Supplier<CompletionStage<String>> decoratedCompletionStageSupplier = CircuitBreaker.decorateCompletionStage(circuitBreaker, completionStageSupplier); CompletionStage<String> decoratedCompletionStage = decoratedCompletionStageSupplier .get() .thenApply(value -> value + " world"); // Then the helloWorldService should be invoked 1 time assertThat(decoratedCompletionStage.toCompletableFuture().get()).isEqualTo("Hello world"); BDDMockito.then(helloWorldService).should(Mockito.times(1)).returnHelloWorld(); CircuitBreaker.Metrics metrics = circuitBreaker.getMetrics(); assertThat(metrics.getNumberOfBufferedCalls()).isEqualTo(1); assertThat(metrics.getNumberOfFailedCalls()).isEqualTo(0); }
@Test public void shouldBufferErrorEvents() { // Given // tag::shouldBufferEvents[] CircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults("testName"); CircularEventConsumer<CircuitBreakerEvent> ringBuffer = new CircularEventConsumer<>(2); circuitBreaker.getEventPublisher().onEvent(ringBuffer); // end::shouldBufferEvents[] assertThat(ringBuffer.getBufferedEvents()).isEmpty(); //When circuitBreaker.onError(0, new RuntimeException("Bla")); circuitBreaker.onError(0, new RuntimeException("Bla")); circuitBreaker.onError(0, new RuntimeException("Bla")); //Then CircuitBreaker.Metrics metrics = circuitBreaker.getMetrics(); assertThat(metrics.getNumberOfBufferedCalls()).isEqualTo(3); assertThat(metrics.getNumberOfFailedCalls()).isEqualTo(3); //Should only store 2 events, because capacity is 2 assertThat(ringBuffer.getBufferedEvents()).hasSize(2); //ringBuffer.getBufferedEvents().forEach(event -> LOG.info(event.toString())); }