public DecorateCheckedSupplier<T> withCircuitBreaker(CircuitBreaker circuitBreaker) { supplier = CircuitBreaker.decorateCheckedSupplier(circuitBreaker, supplier); return this; }
@Test public void shouldInvokeRecoverFunction() { // tag::shouldInvokeRecoverFunction[] // Given CircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults("testName"); // When I decorate my function and invoke the decorated function CheckedFunction0<String> checkedSupplier = CircuitBreaker.decorateCheckedSupplier(circuitBreaker, () -> { throw new RuntimeException("BAM!"); }); Try<String> result = Try.of(checkedSupplier) .recover(throwable -> "Hello Recovery"); // Then the function should be a success, because the exception could be recovered assertThat(result.isSuccess()).isTrue(); // and the result must match the result of the recovery function. assertThat(result.get()).isEqualTo("Hello Recovery"); // end::shouldInvokeRecoverFunction[] }
@Test public void shouldInvokeMap() { // tag::shouldInvokeMap[] // Given CircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults("testName"); // When I decorate my function CheckedFunction0<String> decoratedSupplier = CircuitBreaker .decorateCheckedSupplier(circuitBreaker, () -> "This can be any method which returns: 'Hello"); // and chain an other function with map Try<String> result = Try.of(decoratedSupplier) .map(value -> value + " world'"); // Then the Try Monad returns a Success<String>, if all functions ran successfully. assertThat(result.isSuccess()).isTrue(); assertThat(result.get()).isEqualTo("This can be any method which returns: 'Hello world'"); // end::shouldInvokeMap[] }
@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 shouldDecorateCheckedSupplierAndReturnWithException() throws Throwable { // Given CircuitBreakerRegistry circuitBreakerRegistry = CircuitBreakerRegistry.ofDefaults(); CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker("testName"); CircuitBreaker.Metrics metrics = circuitBreaker.getMetrics(); assertThat(metrics.getNumberOfBufferedCalls()).isEqualTo(0); // Given the HelloWorldService throws an exception BDDMockito.given(helloWorldService.returnHelloWorldWithException()).willThrow(new RuntimeException("BAM!")); //When CheckedFunction0<String> checkedSupplier = CircuitBreaker.decorateCheckedSupplier(circuitBreaker, helloWorldService::returnHelloWorldWithException); //Then Try<String> result = Try.of(checkedSupplier); assertThat(result.isFailure()).isTrue(); assertThat(result.failed().get()).isInstanceOf(RuntimeException.class); assertThat(metrics.getNumberOfBufferedCalls()).isEqualTo(1); assertThat(metrics.getNumberOfFailedCalls()).isEqualTo(1); assertThat(metrics.getNumberOfSuccessfulCalls()).isEqualTo(0); // Then the helloWorldService should be invoked 1 time BDDMockito.then(helloWorldService).should(Mockito.times(1)).returnHelloWorldWithException(); }
@Test public void shouldDecorateCheckedSupplierAndReturnWithSuccess() throws Throwable { // Given CircuitBreakerRegistry circuitBreakerRegistry = CircuitBreakerRegistry.ofDefaults(); CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker("testName"); CircuitBreaker.Metrics metrics = circuitBreaker.getMetrics(); assertThat(metrics.getNumberOfBufferedCalls()).isEqualTo(0); // Given the HelloWorldService returns Hello world BDDMockito.given(helloWorldService.returnHelloWorldWithException()).willReturn("Hello world"); //When CheckedFunction0<String> checkedSupplier = CircuitBreaker.decorateCheckedSupplier(circuitBreaker, helloWorldService::returnHelloWorldWithException); //Then assertThat(checkedSupplier.apply()).isEqualTo("Hello world"); assertThat(metrics.getNumberOfBufferedCalls()).isEqualTo(1); assertThat(metrics.getNumberOfFailedCalls()).isEqualTo(0); assertThat(metrics.getNumberOfSuccessfulCalls()).isEqualTo(1); // Then the helloWorldService should be invoked 1 time BDDMockito.then(helloWorldService).should(Mockito.times(1)).returnHelloWorldWithException(); }
@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); }