diff --git a/resilience4j-documentation/src/docs/asciidoc/addon_guides/ratpack.adoc b/resilience4j-documentation/src/docs/asciidoc/addon_guides/ratpack.adoc index ba3fb2ed79..e197730a2c 100644 --- a/resilience4j-documentation/src/docs/asciidoc/addon_guides/ratpack.adoc +++ b/resilience4j-documentation/src/docs/asciidoc/addon_guides/ratpack.adoc @@ -36,9 +36,18 @@ public class MyModule extends AbstractModule { @Override protected void configure() { - CircuitBreakerConfig config = CircuitBreakerConfig.custom(); - bind(CircuitBreakerRegistry.class).toInstance(CircuitBreakerRegistry.of(config); - install(Resilience4jModule.class); + CircuitBreakerConfig config = CircuitBreakerConfig.custom().build(); + bind(CircuitBreakerRegistry.class).toInstance(CircuitBreakerRegistry.of(config)); + Resilience4jModule module = new Resilience4jModule(); + module.configure(c -> { + c.circuitBreaker("test", circuitBreakerConfig -> + circuitBreakerConfig + .defaults(false) + .automaticTransitionFromOpenToHalfOpen(false) + .failureRateThreshold(25) + ); + }); + install(new Resilience4jModule()); } } ---- @@ -51,40 +60,40 @@ This will only rate limit the `/` endpoint. [source,groovy] ---- ratpack { - bindings { - bindInstance(RateLimiterRegistry, RateLimiterRegistry.ofDefaults()) - module(Resilience4jModule) - } - handlers { - get(new RateLimiterHandler(registry, 'test')) - get { - render 'success' - } - get('a') { - render 'success' - } - } + bindings { + bindInstance(RateLimiterRegistry, RateLimiterRegistry.ofDefaults()) + module(Resilience4jModule) + } + handlers { + get(new RateLimiterHandler(registry, 'test')) + get { + render 'success' + } + get('a') { + render 'success' } + } +} ---- This will rate limit all endpoints against the same `RateLimiter`. [source,groovy] ---- ratpack { - bindings { - bindInstance(RateLimiterRegistry, RateLimiterRegistry.ofDefaults()) - module(Resilience4jModule) - } - handlers { - all(new RateLimiterHandler(registry, 'test')) - get { - render 'success' - } - get('a') { - render 'success' - } - } + bindings { + bindInstance(RateLimiterRegistry, RateLimiterRegistry.ofDefaults()) + module(Resilience4jModule) + } + handlers { + all(new RateLimiterHandler(registry, 'test')) + get { + render 'success' + } + get('a') { + render 'success' } + } +} ---- ==== Promises @@ -95,7 +104,7 @@ that is coming from some sort of I/O source. ===== Bulkhead -You can easily apply a Bulkhead to any Ratpack Promise. +You can easily apply a Bulkhead to any Ratpack Promise, given an existing `Bulkhead` instance called `bulkhead`. [source,java] ---- @@ -107,7 +116,7 @@ public Promise methodWhichReturnsAPromise() { ===== CircuitBreaker -You can easily apply a CircuitBreaker to any Ratpack Promise. +You can easily apply a CircuitBreaker to any Ratpack Promise, given an existing `CircuitBreaker` instance called `circuitBreaker`. [source,java] ---- @@ -117,9 +126,26 @@ public Promise methodWhichReturnsAPromise() { } ---- +You can also specify in-line which exception conditions should be recorded as a failure. In this example when +`MyException` is thrown, it will be recorded as a circuitbreaker failure. Other exceptions will be ignored by +the `circuitBreaker`. + +[source,java] +---- +public Promise methodWhichReturnsAPromise() { + return backendBConnector.methodWhichReturnsAPromise() + .transform( + CircuitBreakerTransformer + .of(circuitBreaker) + .recover(t -> "recovered") + .recordFailurePredicate(e -> e instanceof MyException) + ); +} +---- + ===== Retry -You can easily apply a Retry to any Ratpack Promise. +You can easily apply a Retry to any Ratpack Promise, given an existing `Retry` instance called `retry`. [source,java] ---- @@ -131,7 +157,7 @@ public Promise methodWhichReturnsAPromise() { ===== RateLimiter -You can easily apply a RateLimiter to any Ratpack Promise. +You can easily apply a RateLimiter to any Ratpack Promise, given an existing `RateLimiter` instance called `rateLimiter`. [source,java] ---- @@ -306,6 +332,8 @@ ratpack { } ---- +Note that `recordFailurePredicate` cannot be specified via `yaml` configuration. + [source,yaml] ---- resilience4j: diff --git a/resilience4j-ratpack/src/main/java/io/github/resilience4j/ratpack/Resilience4jModule.java b/resilience4j-ratpack/src/main/java/io/github/resilience4j/ratpack/Resilience4jModule.java index d326489cb0..c9153f4b0e 100644 --- a/resilience4j-ratpack/src/main/java/io/github/resilience4j/ratpack/Resilience4jModule.java +++ b/resilience4j-ratpack/src/main/java/io/github/resilience4j/ratpack/Resilience4jModule.java @@ -177,12 +177,16 @@ public void onStart(StartEvent event) throws Exception { if (circuitBreakerConfig.getDefaults()) { circuitBreaker = circuitBreakerRegistry.circuitBreaker(name); } else { - circuitBreaker = circuitBreakerRegistry.circuitBreaker(name, CircuitBreakerConfig.custom() + CircuitBreakerConfig.Builder builder = CircuitBreakerConfig.custom() .failureRateThreshold(circuitBreakerConfig.getFailureRateThreshold()) .ringBufferSizeInClosedState(circuitBreakerConfig.getRingBufferSizeInClosedState()) .ringBufferSizeInHalfOpenState(circuitBreakerConfig.getRingBufferSizeInHalfOpenState()) .waitDurationInOpenState(Duration.ofMillis(circuitBreakerConfig.getWaitIntervalInMillis())) - .build()); + .recordFailure(circuitBreakerConfig.getRecordFailurePredicate()); + if (circuitBreakerConfig.isAutomaticTransitionFromOpenToHalfOpen()) { + builder.enableAutomaticTransitionFromOpenToHalfOpen(); + } + circuitBreaker = circuitBreakerRegistry.circuitBreaker(name, builder.build()); } if (endpointsConfig.getCircuitBreakers().isEnabled()) { circuitBreaker.getEventPublisher().onEvent(cbConsumerRegistry.createEventConsumer(name, endpointsConfig.getCircuitBreakers().getEventConsumerBufferSize())); diff --git a/resilience4j-ratpack/src/main/java/io/github/resilience4j/ratpack/bulkhead/BulkheadTransformer.java b/resilience4j-ratpack/src/main/java/io/github/resilience4j/ratpack/bulkhead/BulkheadTransformer.java index 820fb2e741..7d96ff3492 100644 --- a/resilience4j-ratpack/src/main/java/io/github/resilience4j/ratpack/bulkhead/BulkheadTransformer.java +++ b/resilience4j-ratpack/src/main/java/io/github/resilience4j/ratpack/bulkhead/BulkheadTransformer.java @@ -17,15 +17,15 @@ import io.github.resilience4j.bulkhead.Bulkhead; import io.github.resilience4j.bulkhead.BulkheadFullException; +import io.github.resilience4j.ratpack.internal.AbstractTransformer; import ratpack.exec.Downstream; import ratpack.exec.Upstream; import ratpack.func.Function; -public class BulkheadTransformer implements Function, Upstream> { +public class BulkheadTransformer extends AbstractTransformer { private final Bulkhead bulkhead; - private Function recover; private BulkheadTransformer(Bulkhead bulkhead) { this.bulkhead = bulkhead; @@ -47,11 +47,11 @@ public static BulkheadTransformer of(Bulkhead bulkhead) { /** * Set a recovery function that will execute when the rateLimiter limit is exceeded. * - * @param recover the recovery function + * @param recoverer the recovery function * @return the transformer */ - public BulkheadTransformer recover(Function recover) { - this.recover = recover; + public BulkheadTransformer recover(Function recoverer) { + this.recoverer = recoverer; return this; } @@ -71,15 +71,7 @@ public void success(T value) { @Override public void error(Throwable throwable) { bulkhead.onComplete(); - try { - if (recover != null) { - down.success(recover.apply(throwable)); - } else { - down.error(throwable); - } - } catch (Throwable t) { - down.error(t); - } + handleRecovery(down, throwable); } @Override @@ -90,15 +82,7 @@ public void complete() { }); } else { Throwable t = new BulkheadFullException(String.format("Bulkhead '%s' is full", bulkhead.getName())); - if (recover != null) { - try { - down.success(recover.apply(t)); - } catch (Throwable t2) { - down.error(t2); - } - } else { - down.error(t); - } + handleRecovery(down, t); } }; } diff --git a/resilience4j-ratpack/src/main/java/io/github/resilience4j/ratpack/circuitbreaker/CircuitBreakerConfig.java b/resilience4j-ratpack/src/main/java/io/github/resilience4j/ratpack/circuitbreaker/CircuitBreakerConfig.java index 7847a2e7b9..f347b3c1a5 100644 --- a/resilience4j-ratpack/src/main/java/io/github/resilience4j/ratpack/circuitbreaker/CircuitBreakerConfig.java +++ b/resilience4j-ratpack/src/main/java/io/github/resilience4j/ratpack/circuitbreaker/CircuitBreakerConfig.java @@ -16,10 +16,9 @@ package io.github.resilience4j.ratpack.circuitbreaker; -import static io.github.resilience4j.circuitbreaker.CircuitBreakerConfig.DEFAULT_MAX_FAILURE_THRESHOLD; -import static io.github.resilience4j.circuitbreaker.CircuitBreakerConfig.DEFAULT_RING_BUFFER_SIZE_IN_CLOSED_STATE; -import static io.github.resilience4j.circuitbreaker.CircuitBreakerConfig.DEFAULT_RING_BUFFER_SIZE_IN_HALF_OPEN_STATE; -import static io.github.resilience4j.circuitbreaker.CircuitBreakerConfig.DEFAULT_WAIT_DURATION_IN_OPEN_STATE; +import java.util.function.Predicate; + +import static io.github.resilience4j.circuitbreaker.CircuitBreakerConfig.*; public class CircuitBreakerConfig { private boolean defaults = false; @@ -27,6 +26,8 @@ public class CircuitBreakerConfig { private Integer failureRateThreshold = DEFAULT_MAX_FAILURE_THRESHOLD; private Integer ringBufferSizeInClosedState = DEFAULT_RING_BUFFER_SIZE_IN_CLOSED_STATE; private Integer ringBufferSizeInHalfOpenState = DEFAULT_RING_BUFFER_SIZE_IN_HALF_OPEN_STATE; + private Predicate recordFailurePredicate = DEFAULT_RECORD_FAILURE_PREDICATE; + private boolean automaticTransitionFromOpenToHalfOpen = false; /** * Use config provided by circuitbreaker registry instead of these config values. @@ -59,6 +60,16 @@ public CircuitBreakerConfig ringBufferSizeInHalfOpenState(Integer ringBufferSize return this; } + public CircuitBreakerConfig recordFailurePredicate(Predicate recordFailurePredicate) { + this.recordFailurePredicate = recordFailurePredicate; + return this; + } + + public CircuitBreakerConfig automaticTransitionFromOpenToHalfOpen(boolean automaticTransitionFromOpenToHalfOpen) { + this.automaticTransitionFromOpenToHalfOpen = automaticTransitionFromOpenToHalfOpen; + return this; + } + public boolean getDefaults() { return defaults; } @@ -79,4 +90,12 @@ public Integer getRingBufferSizeInHalfOpenState() { return ringBufferSizeInHalfOpenState; } + public Predicate getRecordFailurePredicate() { + return recordFailurePredicate; + } + + public boolean isAutomaticTransitionFromOpenToHalfOpen() { + return automaticTransitionFromOpenToHalfOpen; + } + } diff --git a/resilience4j-ratpack/src/main/java/io/github/resilience4j/ratpack/circuitbreaker/CircuitBreakerTransformer.java b/resilience4j-ratpack/src/main/java/io/github/resilience4j/ratpack/circuitbreaker/CircuitBreakerTransformer.java index dc02a7d380..94522b8b9a 100644 --- a/resilience4j-ratpack/src/main/java/io/github/resilience4j/ratpack/circuitbreaker/CircuitBreakerTransformer.java +++ b/resilience4j-ratpack/src/main/java/io/github/resilience4j/ratpack/circuitbreaker/CircuitBreakerTransformer.java @@ -17,17 +17,20 @@ import io.github.resilience4j.circuitbreaker.CircuitBreaker; import io.github.resilience4j.circuitbreaker.CircuitBreakerOpenException; +import io.github.resilience4j.ratpack.internal.AbstractTransformer; import ratpack.exec.Downstream; import ratpack.exec.Upstream; import ratpack.func.Function; -public class CircuitBreakerTransformer implements Function, Upstream> { +import java.util.function.Predicate; +public class CircuitBreakerTransformer extends AbstractTransformer { private final CircuitBreaker circuitBreaker; - private Function recoverer; + private Predicate recordFailurePredicate; private CircuitBreakerTransformer(CircuitBreaker circuitBreaker) { this.circuitBreaker = circuitBreaker; + this.recordFailurePredicate = circuitBreaker.getCircuitBreakerConfig().getRecordFailurePredicate(); } /** @@ -43,6 +46,18 @@ public static CircuitBreakerTransformer of(CircuitBreaker circuitBreaker) return new CircuitBreakerTransformer<>(circuitBreaker); } + /** + * Set predicate for which exceptions should record circuitbreaker failure. + * This will override any values configured in {@link CircuitBreakerConfig}. + * + * @param recordFailurePredicate the predicate. When it evaluates to true, the throwable will record an error. + * @return the transformer + */ + public CircuitBreakerTransformer recordFailurePredicate(Predicate recordFailurePredicate) { + this.recordFailurePredicate = recordFailurePredicate; + return this; + } + /** * Set a recovery function that will execute when the circuit breaker is open. * @@ -72,16 +87,10 @@ public void success(T value) { @Override public void error(Throwable throwable) { long durationInNanos = System.nanoTime() - start; - circuitBreaker.onError(durationInNanos, throwable); - try { - if (recoverer != null) { - down.success(recoverer.apply(throwable)); - } else { - down.error(throwable); - } - } catch (Throwable t) { - down.error(t); + if (recordFailurePredicate.test(throwable)) { + circuitBreaker.onError(durationInNanos, throwable); } + handleRecovery(down, throwable); } @Override @@ -91,15 +100,7 @@ public void complete() { }); } else { Throwable t = new CircuitBreakerOpenException(String.format("CircuitBreaker '%s' is open", circuitBreaker.getName())); - if (recoverer != null) { - try { - down.success(recoverer.apply(t)); - } catch (Throwable t2) { - down.error(t2); - } - } else { - down.error(t); - } + handleRecovery(down, t); } }; } diff --git a/resilience4j-ratpack/src/main/java/io/github/resilience4j/ratpack/internal/AbstractTransformer.java b/resilience4j-ratpack/src/main/java/io/github/resilience4j/ratpack/internal/AbstractTransformer.java new file mode 100644 index 0000000000..a99cff7b08 --- /dev/null +++ b/resilience4j-ratpack/src/main/java/io/github/resilience4j/ratpack/internal/AbstractTransformer.java @@ -0,0 +1,38 @@ +/* + * Copyright 2018 Dan Maas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.github.resilience4j.ratpack.internal; + +import ratpack.exec.Downstream; +import ratpack.exec.Upstream; +import ratpack.func.Function; + +public abstract class AbstractTransformer implements Function, Upstream> { + + protected Function recoverer; + + protected void handleRecovery(Downstream down, Throwable throwable) { + try { + if (recoverer != null) { + down.success(recoverer.apply(throwable)); + } else { + down.error(throwable); + } + } catch (Throwable t) { + down.error(t); + } + } +} diff --git a/resilience4j-ratpack/src/main/java/io/github/resilience4j/ratpack/ratelimiter/RateLimiterTransformer.java b/resilience4j-ratpack/src/main/java/io/github/resilience4j/ratpack/ratelimiter/RateLimiterTransformer.java index d8a4422d5e..e644d97a69 100644 --- a/resilience4j-ratpack/src/main/java/io/github/resilience4j/ratpack/ratelimiter/RateLimiterTransformer.java +++ b/resilience4j-ratpack/src/main/java/io/github/resilience4j/ratpack/ratelimiter/RateLimiterTransformer.java @@ -18,16 +18,16 @@ import io.github.resilience4j.ratelimiter.RateLimiter; import io.github.resilience4j.ratelimiter.RateLimiterConfig; import io.github.resilience4j.ratelimiter.RequestNotPermitted; +import io.github.resilience4j.ratpack.internal.AbstractTransformer; import ratpack.exec.Downstream; import ratpack.exec.Upstream; import ratpack.func.Function; import java.time.Duration; -public class RateLimiterTransformer implements Function, Upstream> { +public class RateLimiterTransformer extends AbstractTransformer { private final RateLimiter rateLimiter; - private Function recover; private RateLimiterTransformer(RateLimiter rateLimiter) { this.rateLimiter = rateLimiter; @@ -48,11 +48,11 @@ public static RateLimiterTransformer of(RateLimiter rateLimiter) { /** * Set a recovery function that will execute when the rateLimiter limit is exceeded. * - * @param recover the recovery function + * @param recoverer the recovery function * @return the transformer */ - public RateLimiterTransformer recover(Function recover) { - this.recover = recover; + public RateLimiterTransformer recover(Function recoverer) { + this.recoverer = recoverer; return this; } @@ -67,8 +67,8 @@ public Upstream apply(Upstream upstream) throws Exception { } if (!permission) { Throwable t = new RequestNotPermitted("Request not permitted for limiter: " + rateLimiter.getName()); - if (recover != null) { - down.success(recover.apply(t)); + if (recoverer != null) { + down.success(recoverer.apply(t)); } else { down.error(t); } diff --git a/resilience4j-ratpack/src/main/java/io/github/resilience4j/ratpack/retry/RetryTransformer.java b/resilience4j-ratpack/src/main/java/io/github/resilience4j/ratpack/retry/RetryTransformer.java index 81abf8677e..fd0ad586f1 100644 --- a/resilience4j-ratpack/src/main/java/io/github/resilience4j/ratpack/retry/RetryTransformer.java +++ b/resilience4j-ratpack/src/main/java/io/github/resilience4j/ratpack/retry/RetryTransformer.java @@ -15,15 +15,15 @@ */ package io.github.resilience4j.ratpack.retry; +import io.github.resilience4j.ratpack.internal.AbstractTransformer; import io.github.resilience4j.retry.Retry; import ratpack.exec.Downstream; import ratpack.exec.Upstream; import ratpack.func.Function; -public class RetryTransformer implements Function, Upstream> { +public class RetryTransformer extends AbstractTransformer { private final Retry retry; - private Function recoverer; private RetryTransformer(Retry retry) { this.retry = retry; diff --git a/resilience4j-ratpack/src/test/groovy/io/github/resilience4j/ratpack/Resilience4jModuleSpec.groovy b/resilience4j-ratpack/src/test/groovy/io/github/resilience4j/ratpack/Resilience4jModuleSpec.groovy index fd9e3592f7..55815608a4 100644 --- a/resilience4j-ratpack/src/test/groovy/io/github/resilience4j/ratpack/Resilience4jModuleSpec.groovy +++ b/resilience4j-ratpack/src/test/groovy/io/github/resilience4j/ratpack/Resilience4jModuleSpec.groovy @@ -59,6 +59,9 @@ class Resilience4jModuleSpec extends Specification { .waitIntervalInMillis(5000) .ringBufferSizeInClosedState(200) .ringBufferSizeInHalfOpenState(20) + .failureRateThreshold(60) + .automaticTransitionFromOpenToHalfOpen(true) + .recordFailurePredicate { true } } } } @@ -86,6 +89,7 @@ class Resilience4jModuleSpec extends Specification { assert ringBufferSizeInHalfOpenState == 10 assert waitDurationInOpenState == Duration.ofMinutes(1) assert failureRateThreshold == 50 + assert !automaticTransitionFromOpenToHalfOpenEnabled it } def test2 = circuitBreakerRegistry.circuitBreaker('test2') @@ -94,7 +98,9 @@ class Resilience4jModuleSpec extends Specification { assert ringBufferSizeInClosedState == 200 assert ringBufferSizeInHalfOpenState == 20 assert waitDurationInOpenState == Duration.ofMillis(5000) - assert failureRateThreshold == 50 + assert failureRateThreshold == 60 + assert automaticTransitionFromOpenToHalfOpenEnabled + assert recordFailurePredicate.test(new Exception()) it } } @@ -166,6 +172,8 @@ class Resilience4jModuleSpec extends Specification { assert ringBufferSizeInHalfOpenState == 10 assert waitDurationInOpenState == Duration.ofMinutes(1) assert failureRateThreshold == 50 + assert !automaticTransitionFromOpenToHalfOpenEnabled + assert recordFailurePredicate.test(new Exception()) it } def test2 = circuitBreakerRegistry.circuitBreaker('test2') @@ -174,7 +182,9 @@ class Resilience4jModuleSpec extends Specification { assert ringBufferSizeInClosedState == 200 assert ringBufferSizeInHalfOpenState == 20 assert waitDurationInOpenState == Duration.ofMillis(5000) - assert failureRateThreshold == 50 + assert failureRateThreshold == 60 + assert automaticTransitionFromOpenToHalfOpenEnabled + assert recordFailurePredicate.test(new Exception()) it } } diff --git a/resilience4j-ratpack/src/test/groovy/io/github/resilience4j/ratpack/circuitbreaker/CircuitBreakerTransformerSpec.groovy b/resilience4j-ratpack/src/test/groovy/io/github/resilience4j/ratpack/circuitbreaker/CircuitBreakerTransformerSpec.groovy index 6ad49ad348..64b148e8b7 100644 --- a/resilience4j-ratpack/src/test/groovy/io/github/resilience4j/ratpack/circuitbreaker/CircuitBreakerTransformerSpec.groovy +++ b/resilience4j-ratpack/src/test/groovy/io/github/resilience4j/ratpack/circuitbreaker/CircuitBreakerTransformerSpec.groovy @@ -15,8 +15,11 @@ */ package io.github.resilience4j.ratpack.circuitbreaker +import groovy.transform.Canonical +import groovy.transform.TupleConstructor import io.github.resilience4j.circuitbreaker.CircuitBreaker import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig +import io.github.resilience4j.circuitbreaker.CircuitBreakerOpenException import io.github.resilience4j.ratpack.circuitbreaker.CircuitBreakerTransformer import ratpack.exec.Blocking import ratpack.test.exec.ExecHarness @@ -144,6 +147,45 @@ class CircuitBreakerTransformerSpec extends Specification { breaker.state == CircuitBreaker.State.CLOSED } + def "test that only specific exceptions are recorded as errors"() { + given: + CircuitBreaker breaker = buildBreaker() + CircuitBreakerTransformer transformer = CircuitBreakerTransformer + .of(breaker) + .recordFailurePredicate { it instanceof DummyException2 } + Exception e1 = new DummyException1("puke") + Exception e2 = new DummyException2("puke") + + when: + def r = null + (1..10).forEach { + r = ExecHarness.yieldSingle { + Blocking. get { throw e1 } + .transform(transformer) + } + } + + then: + r.value == null + r.error + r.throwable == e1 + breaker.state == CircuitBreaker.State.CLOSED + + when: + (1..10).forEach { + r = ExecHarness.yieldSingle { + Blocking. get { throw e2 } + .transform(transformer) + } + } + + then: + r.value == null + r.error + r.throwable instanceof CircuitBreakerOpenException + breaker.state == CircuitBreaker.State.OPEN + } + def buildBreaker() { CircuitBreakerConfig config = CircuitBreakerConfig.custom() .failureRateThreshold(50) @@ -155,3 +197,15 @@ class CircuitBreakerTransformerSpec extends Specification { } } + +class DummyException1 extends Exception { + DummyException1(String message) { + super(message) + } +} + +class DummyException2 extends Exception { + DummyException2(String message) { + super(message) + } +} diff --git a/resilience4j-ratpack/src/test/resources/application.yml b/resilience4j-ratpack/src/test/resources/application.yml index 0ea7a3513d..b20e3a6514 100644 --- a/resilience4j-ratpack/src/test/resources/application.yml +++ b/resilience4j-ratpack/src/test/resources/application.yml @@ -23,7 +23,8 @@ resilience4j: ringBufferSizeInClosedState: 200 ringBufferSizeInHalfOpenState: 20 waitIntervalInMillis: 5000 - failureRateThreshold: 50 + failureRateThreshold: 60 + automaticTransitionFromOpenToHalfOpen: true rateLimiters: test1: defaults: true