@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 CircuitBreakerRegistry circuitBreakerRegistry = CircuitBreakerRegistry.of(circuitBreakerConfig); CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker("testName"); circuitBreaker.recordFailure(new RuntimeException()); circuitBreaker.recordFailure(new RuntimeException()); assertThat(circuitBreaker.getState()).isEqualTo(CircuitBreaker.State.OPEN); // When Try.CheckedRunnable checkedRunnable = CircuitBreaker.decorateCheckedRunnable( () -> { throw new RuntimeException("BAM!"); }, circuitBreaker); Try result = Try.run(checkedRunnable); // Then assertThat(result.isFailure()).isTrue(); assertThat(result.failed().get()).isInstanceOf(CircuitBreakerOpenException.class); }
@Test public void shouldThrowCircuitBreakerOpenException() { // tag::shouldThrowCircuitBreakerOpenException[] // Given CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom() .ringBufferSizeInClosedState(2) .waitDurationInOpenState(Duration.ofMillis(1000)) .build(); CircuitBreakerRegistry circuitBreakerRegistry = CircuitBreakerRegistry.of(circuitBreakerConfig); CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker("uniqueName"); // Simulate a failure attempt circuitBreaker.recordFailure(new RuntimeException()); // CircuitBreaker is still CLOSED, because 1 failure is allowed assertThat(circuitBreaker.getState()).isEqualTo(CircuitBreaker.State.CLOSED); // Simulate a failure attempt circuitBreaker.recordFailure(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(() -> "Hello", circuitBreaker)) .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[] }
@Test public void shouldNotRecordIOExceptionAsAFailure() { // tag::shouldNotRecordIOExceptionAsAFailure[] // Given CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom() .ringBufferSizeInClosedState(2) .ringBufferSizeInHalfOpenState(2) .waitDurationInOpenState(Duration.ofMillis(1000)) .recordFailure( throwable -> API.Match(throwable) .of(Case(instanceOf(WebServiceException.class), true), Case($(), false))) .build(); CircuitBreakerRegistry circuitBreakerRegistry = CircuitBreakerRegistry.of(circuitBreakerConfig); CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker("testName"); // Simulate a failure attempt circuitBreaker.recordFailure(new RuntimeException()); // CircuitBreaker is still CLOSED, because 1 failure is allowed assertThat(circuitBreaker.getState()).isEqualTo(CircuitBreaker.State.CLOSED); // When Try.CheckedRunnable checkedRunnable = CircuitBreaker.decorateCheckedRunnable( () -> { throw new SocketTimeoutException("BAM!"); }, circuitBreaker); Try result = Try.run(checkedRunnable); // Then assertThat(result.isFailure()).isTrue(); // CircuitBreaker is still CLOSED, because SocketTimeoutException has not been recorded as a // failure assertThat(circuitBreaker.getState()).isEqualTo(CircuitBreaker.State.CLOSED); assertThat(result.failed().get()).isInstanceOf(IOException.class); // end::shouldNotRecordIOExceptionAsAFailure[] }
@Test(expected = IllegalArgumentException.class) public void zeroWaitIntervalShouldFail() { CircuitBreakerConfig.custom().waitInterval(0).build(); }
@Test(expected = IllegalArgumentException.class) public void zeroMaxFailuresShouldFail() { CircuitBreakerConfig.custom().maxFailures(0).build(); }