} else { CircuitBreakerConfig.Builder builder = CircuitBreakerConfig.custom() .failureRateThreshold(circuitBreakerConfig.getFailureRateThreshold()) .ringBufferSizeInClosedState(circuitBreakerConfig.getRingBufferSizeInClosedState()) .ringBufferSizeInHalfOpenState(circuitBreakerConfig.getRingBufferSizeInHalfOpenState()) .waitDurationInOpenState(Duration.ofMillis(circuitBreakerConfig.getWaitIntervalInMillis())) .recordExceptions(circuitBreakerConfig.getRecordExceptionClasses()) .ignoreExceptions(circuitBreakerConfig.getIgnoreExceptionClasses()); if (circuitBreakerConfig.isAutomaticTransitionFromOpenToHalfOpen()) { builder.enableAutomaticTransitionFromOpenToHalfOpen(); circuitBreaker = circuitBreakerRegistry.circuitBreaker(name, builder.build());
.ringBufferSizeInClosedState(2) .ringBufferSizeInHalfOpenState(2) .waitDurationInOpenState(Duration.ofMillis(1000)) .recordFailure(throwable -> Match(throwable).of( Case($(instanceOf(WebServiceException.class)), true), Case($(), false))) .build(); CircuitBreaker circuitBreaker = CircuitBreaker.of("testName", circuitBreakerConfig);
} else { CircuitBreakerConfig.Builder builder = CircuitBreakerConfig.custom() .failureRateThreshold(circuitBreakerConfig.getFailureRateThreshold()) .ringBufferSizeInClosedState(circuitBreakerConfig.getRingBufferSizeInClosedState()) .ringBufferSizeInHalfOpenState(circuitBreakerConfig.getRingBufferSizeInHalfOpenState()) .waitDurationInOpenState(Duration.ofMillis(circuitBreakerConfig.getWaitIntervalInMillis())) .recordExceptions(circuitBreakerConfig.getRecordExceptionClasses()) .ignoreExceptions(circuitBreakerConfig.getIgnoreExceptionClasses()); if (circuitBreakerConfig.isAutomaticTransitionFromOpenToHalfOpen()) { builder.enableAutomaticTransitionFromOpenToHalfOpen(); circuitBreaker = circuitBreakerRegistry.circuitBreaker(name, builder.build());
public Builder buildCircuitBreakerConfig(BackendProperties properties) { if (properties == null) { return new Builder(); } Builder builder = CircuitBreakerConfig.custom(); if (properties.getWaitDurationInOpenState() != null) { builder.waitDurationInOpenState(properties.getWaitDurationInOpenState()); } if (properties.getFailureRateThreshold() != null) { builder.failureRateThreshold(properties.getFailureRateThreshold()); } if (properties.getRingBufferSizeInClosedState() != null) { builder.ringBufferSizeInClosedState(properties.getRingBufferSizeInClosedState()); } if (properties.getRingBufferSizeInHalfOpenState() != null) { builder.ringBufferSizeInHalfOpenState(properties.getRingBufferSizeInHalfOpenState()); } if (properties.recordFailurePredicate != null) { buildRecordFailurePredicate(properties, builder); } if (properties.recordExceptions != null) { builder.recordExceptions(properties.recordExceptions); } if (properties.ignoreExceptions != null) { builder.ignoreExceptions(properties.ignoreExceptions); } return builder; }
private CircuitBreakerConfig createCircuitBreakerConfig(BackendProperties backendProperties) { return buildCircuitBreakerConfig(backendProperties).build(); }
protected void buildRecordFailurePredicate(BackendProperties properties, Builder builder) { builder.recordFailure(BeanUtils.instantiateClass(properties.getRecordFailurePredicate())); }
@Before public void setUp() { CircuitBreakerConfig circuitBreakerConfigGroupA = CircuitBreakerConfig.custom() .failureRateThreshold(50) .ringBufferSizeInClosedState(5) .ringBufferSizeInHalfOpenState(3) .enableAutomaticTransitionFromOpenToHalfOpen() .waitDurationInOpenState(Duration.ofSeconds(2)) .recordFailure(error -> !(error instanceof NumberFormatException)) .build(); .failureRateThreshold(50) .ringBufferSizeInClosedState(5) .ringBufferSizeInHalfOpenState(3) .enableAutomaticTransitionFromOpenToHalfOpen() .waitDurationInOpenState(Duration.ofSeconds(1)) .recordFailure(error -> !(error instanceof NumberFormatException)) .build();
@Test public void testEmitter() throws IOException { CircuitBreakerConfig config = CircuitBreakerConfig.custom() .ringBufferSizeInClosedState(3) .ringBufferSizeInHalfOpenState(2) .failureRateThreshold(66) .waitDurationInOpenState(Duration.ofSeconds(1)) .recordFailure(e -> !(e instanceof IllegalArgumentException)) .build();
.ringBufferSizeInClosedState(3) .recordFailure(throwable -> API.Match(throwable).of( Case($(instanceOf(WebServiceException.class)), true), Case($(), false))) .build(); CircuitBreaker circuitBreaker = CircuitBreaker.of("testName", circuitBreakerConfig); CircularEventConsumer<CircuitBreakerEvent> ringBuffer = new CircularEventConsumer<>(10);
.ringBufferSizeInClosedState(2) .ringBufferSizeInHalfOpenState(2) .failureRateThreshold(50) .waitDurationInOpenState(Duration.ofMillis(1000)) .build();
@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); }
public Builder buildCircuitBreakerConfig(BackendProperties properties) { if (properties == null) { return new Builder(); } Builder builder = CircuitBreakerConfig.custom(); if (properties.getWaitDurationInOpenState() != null) { builder.waitDurationInOpenState(properties.getWaitDurationInOpenState()); } if (properties.getFailureRateThreshold() != null) { builder.failureRateThreshold(properties.getFailureRateThreshold()); } if (properties.getRingBufferSizeInClosedState() != null) { builder.ringBufferSizeInClosedState(properties.getRingBufferSizeInClosedState()); } if (properties.getRingBufferSizeInHalfOpenState() != null) { builder.ringBufferSizeInHalfOpenState(properties.getRingBufferSizeInHalfOpenState()); } if (properties.recordFailurePredicate != null) { buildRecordFailurePredicate(properties, builder); } if (properties.recordExceptions != null) { builder.recordExceptions(properties.recordExceptions); } if (properties.ignoreExceptions != null) { builder.ignoreExceptions(properties.ignoreExceptions); } return builder; }
@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 shouldNotProduceEventsInDisabledState() { //Given circuitBreaker = CircuitBreaker.of("test", CircuitBreakerConfig.custom() .ringBufferSizeInClosedState(1).build()); circuitBreaker.getEventPublisher() .onEvent(this::logEventType); //When we transition to disabled circuitBreaker.transitionToDisabledState(); //And we execute other calls that should generate events circuitBreaker.onError(1000, new IOException("BAM!")); circuitBreaker.onError(1000, new IOException("BAM!")); circuitBreaker.isCallPermitted(); circuitBreaker.onSuccess(0); circuitBreaker.onError(1000, new IOException("BAM!")); //Then we do not produce events then(logger).should(times(1)).info("STATE_TRANSITION"); then(logger).should(times(0)).info("NOT_PERMITTED"); then(logger).should(times(0)).info("SUCCESS"); then(logger).should(times(0)).info("ERROR"); then(logger).should(times(0)).info("IGNORED_ERROR"); }
@Test() public void shouldUseBothRecordToBuildPredicate() { CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom() .recordFailure(TEST_PREDICATE) //1 .recordExceptions(RuntimeException.class, ExtendsExtendsException.class) //2 .ignoreExceptions(ExtendsException.class, ExtendsRuntimeException.class) //3 .build(); final Predicate<? super Throwable> failurePredicate = circuitBreakerConfig.getRecordFailurePredicate(); then(failurePredicate.test(new Exception())).isEqualTo(false); // not explicitly included then(failurePredicate.test(new Exception("test"))).isEqualTo(true); // explicitly included by 1 then(failurePredicate.test(new ExtendsError())).isEqualTo(false); // ot explicitly included then(failurePredicate.test(new ExtendsException())).isEqualTo(false); // explicitly excluded by 3 then(failurePredicate.test(new ExtendsException("test"))).isEqualTo(false); // explicitly excluded by 3 even if included by 1 then(failurePredicate.test(new ExtendsException2())).isEqualTo(false); // not explicitly included then(failurePredicate.test(new RuntimeException())).isEqualTo(true); // explicitly included by 2 then(failurePredicate.test(new ExtendsRuntimeException())).isEqualTo(false); // explicitly excluded by 3 then(failurePredicate.test(new ExtendsExtendsException())).isEqualTo(false); // inherits excluded from ExtendsException by 3 }
private CircuitBreakerConfig createCircuitBreakerConfig(BackendProperties backendProperties) { return buildCircuitBreakerConfig(backendProperties).build(); }
@Test() public void shouldUseIgnoreExceptionOverRecordToBuildPredicate() { CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom() .recordExceptions(RuntimeException.class, ExtendsExtendsException.class) .ignoreExceptions(ExtendsException.class, ExtendsRuntimeException.class) .build(); final Predicate<? super Throwable> failurePredicate = circuitBreakerConfig.getRecordFailurePredicate(); then(failurePredicate.test(new Exception())).isEqualTo(false); // not explicitly included then(failurePredicate.test(new ExtendsError())).isEqualTo(false); // not explicitly included then(failurePredicate.test(new ExtendsException())).isEqualTo(false); // explicitly excluded then(failurePredicate.test(new ExtendsException2())).isEqualTo(false); // not explicitly included then(failurePredicate.test(new RuntimeException())).isEqualTo(true); // explicitly included then(failurePredicate.test(new ExtendsRuntimeException())).isEqualTo(false); // explicitly excluded then(failurePredicate.test(new ExtendsExtendsException())).isEqualTo(false); // inherits excluded from ExtendsException }
protected void buildRecordFailurePredicate(BackendProperties properties, Builder builder) { builder.recordFailure(BeanUtils.instantiateClass(properties.getRecordFailurePredicate())); }
@Test public void shouldConsumeIgnoredErrorEvent() { CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom() .recordFailure(throwable -> Match(throwable).of( Case($(instanceOf(WebServiceException.class)), true), Case($(), false))) .build(); circuitBreaker = CircuitBreaker.of("test", circuitBreakerConfig); circuitBreaker.getEventPublisher() .onIgnoredError(this::logEventType) ; circuitBreaker.onError(1000, new IOException("BAM!")); then(logger).should(times(1)).info("IGNORED_ERROR"); }
@Test(expected = IllegalArgumentException.class) public void zeroFailureRateThresholdShouldFail() { CircuitBreakerConfig.custom().failureRateThreshold(0).build(); }