Skip to content

Commit a8b7101

Browse files
Dan MaasRobWin
Dan Maas
authored andcommitted
Issue ReactiveX#74: adding ratpack docs and fixing some configuration issues
* adding docs and fixing some configuration issues, closes ReactiveX#74 * removing unused import
1 parent 987c3f7 commit a8b7101

File tree

8 files changed

+235
-106
lines changed

8 files changed

+235
-106
lines changed

resilience4j-ratpack/README.adoc

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
= resilience4j-ratpack
2+
3+
== Gradle
4+
5+
```
6+
repositories {
7+
maven { url 'http://oss.jfrog.org/artifactory/oss-snapshot-local/' }
8+
mavenCentral()
9+
}
10+
11+
12+
dependencies {
13+
compile('io.github.resilience4j:resilience4j-ratpack:0.9.0-SNAPSHOT')
14+
}
15+
```
16+
17+
== Promises
18+
19+
Ratpack promises provide the means by which an application can become fully non-blocking and asynchronous.
20+
Resilience4j provides transformers that can be applied to Promises. This is ideal when promising a value
21+
that is coming from some sort of I/O source.
22+
23+
=== CircuitBreaker
24+
25+
You can easily apply a CircuitBreaker to any Ratpack Promise.
26+
27+
[source,java]
28+
----
29+
public Promise<String> methodWhichReturnsAPromise() {
30+
return backendBConnector.methodWhichReturnsAPromise()
31+
.transform(CircuitBreakerTransformer.of(circuitBreaker).recover(t -> "recovered"));
32+
}
33+
----
34+
35+
=== Retry
36+
37+
You can easily apply a Retry to any Ratpack Promise.
38+
39+
[source,java]
40+
----
41+
public Promise<String> methodWhichReturnsAPromise() {
42+
return backendBConnector.methodWhichReturnsAPromise()
43+
.transform(RetryTransformer.of(retry).recover(t -> "recovered"));
44+
}
45+
----
46+
47+
=== RateLimiter
48+
49+
You can easily apply a RateLimiter to any Ratpack Promise.
50+
51+
[source,java]
52+
----
53+
public Promise<String> methodWhichReturnsAPromise() {
54+
return backendBConnector.methodWhichReturnsAPromise()
55+
.transform(RateLimiterTransformer.of(rateLimiter).recover(t -> "recovered"));
56+
}
57+
----
58+
59+
== Guice AOP
60+
61+
Guice provides method interception capabilities. Here are provided some annotations which allow
62+
methods returning promises, completion stage, and normal values, to be operated on.
63+
64+
=== CircuitBreaker
65+
The demo shows how to use the `CircuitBreaker` annotation to make your Ratpack application more fault tolerant.
66+
You can either annotate a class in order to protect all public methods or just some specific methods.
67+
For example:
68+
69+
[source,java]
70+
----
71+
@CircuitBreaker(name = "backendA", recovery = MyRecoveryFunction.class)
72+
@Singleton
73+
public class BackendAConnector implements Connector {
74+
...
75+
}
76+
----
77+
Where `MyRecoveryFunction` is implements `io.github.resilience4j.ratpack.RecoveryFunction` and provides
78+
a fallback value that is returned when the circuit breaker identified by `name` is open.
79+
80+
=== Retry
81+
TODO
82+
Retry will be supported once the concept of a RetryRegistry is in place.
83+
84+
=== RateLimiter
85+
The demo shows how to use the `RateLimiter` annotation to make your Ratpack application more fault tolerant.
86+
You can either annotate a class in order to protect all public methods or just some specific methods.
87+
For example:
88+
89+
[source,java]
90+
----
91+
@RateLimiter(name = "backendA", recovery = MyRecoveryFunction.class)
92+
@Singleton
93+
public class BackendAConnector implements Connector {
94+
...
95+
}
96+
----
97+
Where `MyRecoveryFunction` is implements `io.github.resilience4j.ratpack.RecoveryFunction` and provides
98+
a fallback value that is returned when the rate limiter rate limit identified by `name` is exceeded.
99+
100+
== Functional style
101+
102+
You can still use a functional programming style for CircuitBreaker, Retry, and RateLimiter. For example:
103+
104+
[source,java]
105+
----
106+
@Singleton
107+
public class BusinessBService implements BusinessService {
108+
109+
public Try<String> methodWithRecovery() {
110+
Try.CheckedSupplier<String> backendFunction = CircuitBreaker.decorateCheckedSupplier(circuitBreaker, () -> backendBConnector.failure());
111+
return Try.of(backendFunction)
112+
.recover((throwable) -> recovery(throwable));
113+
}
114+
115+
private String recovery(Throwable throwable) {
116+
// Handle exception and invoke fallback
117+
return "Hello world from recovery";
118+
}
119+
120+
}
121+
----
122+
123+
== Monitoring
124+
TODO
125+
Ratpack provides the concept of a health check. See https://ratpack.io/manual/current/api/ratpack/health/HealthCheckHandler.html for details.
126+
CircuitBreaker, RateLimiter, and Retry health checks have not been implemented yet.
127+
When implemented they should function similarly to the spring boot health checks.
128+
129+
== Configuration
130+
131+
You must install the `ResilienceModule` if you want to use AOP so that the method interceptors work.
132+
You can optionally configure your CircuitBreakers, RateLimiters, and Retries in your Guice Module as well.
133+
134+
Note: If you don't register a `CircuitBreakerRegistry` or `RateLimiterRegistry`, the defaults
135+
will be used when using AOP.
136+
137+
For example
138+
139+
[source,java]
140+
----
141+
public class MyModule extends AbstractModule {
142+
143+
@Override
144+
protected void configure() {
145+
CircuitBreakerConfig config = CircuitBreakerConfig.custom();
146+
bind(CircuitBreakerRegistry.class).toInstance(CircuitBreakerRegistry.of(config);
147+
install(ResilienceModule.class);
148+
}
149+
}
150+
----
151+
152+
== CircuitBreaker Event Monitoring
153+
TODO
154+
Handlers for displaying the last X CircuitBreaker, Ratelimiter, or Retry events are not yet implemented.
155+
When implemented they should function similarly to the spring boot management endpoints.
156+
157+
== License
158+
159+
Copyright 2017 Dan Maas
160+
161+
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
162+
163+
http://www.apache.org/licenses/LICENSE-2.0
164+
165+
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.

resilience4j-ratpack/src/main/java/io/github/resilience4j/ratpack/ResilienceModule.java

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,35 +15,24 @@
1515
*/
1616
package io.github.resilience4j.ratpack;
1717

18+
import com.google.inject.AbstractModule;
1819
import com.google.inject.matcher.Matchers;
19-
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
20-
import io.github.resilience4j.ratelimiter.RateLimiterRegistry;
2120
import io.github.resilience4j.ratpack.annotation.CircuitBreaker;
2221
import io.github.resilience4j.ratpack.annotation.RateLimiter;
2322
import io.github.resilience4j.ratpack.internal.CircuitBreakerMethodInterceptor;
2423
import io.github.resilience4j.ratpack.internal.RateLimiterMethodInterceptor;
25-
import ratpack.guice.ConfigurableModule;
2624

27-
public class ResilienceModule extends ConfigurableModule<ResilienceModule.ResilienceConfig> {
25+
public class ResilienceModule extends AbstractModule {
2826

2927
@Override
3028
protected void configure() {
31-
bindInterceptor(Matchers.any(), Matchers.annotatedWith(CircuitBreaker.class), injected(new CircuitBreakerMethodInterceptor(getProvider(CircuitBreakerRegistry.class))));
32-
bindInterceptor(Matchers.any(), Matchers.annotatedWith(RateLimiter.class), injected(new RateLimiterMethodInterceptor(getProvider(RateLimiterRegistry.class))));
29+
bindInterceptor(Matchers.any(), Matchers.annotatedWith(CircuitBreaker.class), injected(new CircuitBreakerMethodInterceptor()));
30+
bindInterceptor(Matchers.any(), Matchers.annotatedWith(RateLimiter.class), injected(new RateLimiterMethodInterceptor()));
3331
}
3432

3533
private <T> T injected(T instance) {
3634
requestInjection(instance);
3735
return instance;
3836
}
3937

40-
public static class ResilienceConfig {
41-
private boolean enableMetrics = false;
42-
43-
public ResilienceConfig enableMetrics(boolean enableMetrics) {
44-
this.enableMetrics = enableMetrics;
45-
return this;
46-
}
47-
48-
}
4938
}

resilience4j-ratpack/src/main/java/io/github/resilience4j/ratpack/internal/CircuitBreakerMethodInterceptor.java

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
*/
1616
package io.github.resilience4j.ratpack.internal;
1717

18-
import com.google.inject.Provider;
18+
import com.google.inject.Inject;
1919
import io.github.resilience4j.circuitbreaker.CircuitBreakerOpenException;
2020
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
2121
import io.github.resilience4j.circuitbreaker.operator.CircuitBreakerOperator;
@@ -29,7 +29,6 @@
2929
import org.aopalliance.intercept.MethodInvocation;
3030
import ratpack.exec.Promise;
3131

32-
import javax.inject.Inject;
3332
import java.time.Duration;
3433
import java.util.concurrent.CompletableFuture;
3534
import java.util.concurrent.CompletionStage;
@@ -41,18 +40,20 @@
4140
*/
4241
public class CircuitBreakerMethodInterceptor implements MethodInterceptor {
4342

44-
private final Provider<CircuitBreakerRegistry> provider;
43+
@Inject(optional = true)
44+
private CircuitBreakerRegistry registry;
4545

46-
@Inject
47-
public CircuitBreakerMethodInterceptor(Provider<CircuitBreakerRegistry> provider) {
48-
this.provider = provider;
46+
public CircuitBreakerMethodInterceptor() {
47+
if (registry == null) {
48+
registry = CircuitBreakerRegistry.ofDefaults();
49+
}
4950
}
5051

5152
@SuppressWarnings("unchecked")
5253
@Override
5354
public Object invoke(MethodInvocation invocation) throws Throwable {
5455
CircuitBreaker annotation = invocation.getMethod().getAnnotation(CircuitBreaker.class);
55-
io.github.resilience4j.circuitbreaker.CircuitBreaker breaker = provider.get().circuitBreaker(annotation.name());
56+
io.github.resilience4j.circuitbreaker.CircuitBreaker breaker = registry.circuitBreaker(annotation.name());
5657
if (breaker == null) {
5758
return invocation.proceed();
5859
}

resilience4j-ratpack/src/main/java/io/github/resilience4j/ratpack/internal/CircuitBreakerProvider.java

Lines changed: 0 additions & 37 deletions
This file was deleted.

resilience4j-ratpack/src/main/java/io/github/resilience4j/ratpack/internal/RateLimiterMethodInterceptor.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,17 @@
1616

1717
package io.github.resilience4j.ratpack.internal;
1818

19-
import com.google.inject.Provider;
20-
19+
import com.google.inject.Inject;
2120
import io.github.resilience4j.ratelimiter.RateLimiterConfig;
2221
import io.github.resilience4j.ratelimiter.RateLimiterRegistry;
2322
import io.github.resilience4j.ratelimiter.RequestNotPermitted;
24-
import io.github.resilience4j.ratpack.annotation.RateLimiter;
2523
import io.github.resilience4j.ratpack.RateLimiterTransformer;
2624
import io.github.resilience4j.ratpack.RecoveryFunction;
25+
import io.github.resilience4j.ratpack.annotation.RateLimiter;
2726
import org.aopalliance.intercept.MethodInterceptor;
2827
import org.aopalliance.intercept.MethodInvocation;
2928
import ratpack.exec.Promise;
3029

31-
import javax.inject.Inject;
3230
import java.time.Duration;
3331
import java.util.concurrent.CompletableFuture;
3432
import java.util.concurrent.CompletionStage;
@@ -40,19 +38,21 @@
4038
*/
4139
public class RateLimiterMethodInterceptor implements MethodInterceptor {
4240

43-
private final Provider<RateLimiterRegistry> provider;
41+
@Inject(optional = true)
42+
private RateLimiterRegistry registry;
4443

45-
@Inject
46-
public RateLimiterMethodInterceptor(Provider<RateLimiterRegistry> provider) {
47-
this.provider = provider;
44+
public RateLimiterMethodInterceptor() {
45+
if (registry == null) {
46+
registry = RateLimiterRegistry.of(RateLimiterConfig.ofDefaults());
47+
}
4848
}
4949

5050
@SuppressWarnings("unchecked")
5151
@Override
5252
public Object invoke(MethodInvocation invocation) throws Throwable {
5353
RateLimiter annotation = invocation.getMethod().getAnnotation(RateLimiter.class);
5454
RecoveryFunction<?> recoveryFunction = annotation.recovery().newInstance();
55-
io.github.resilience4j.ratelimiter.RateLimiter rateLimiter = provider.get().rateLimiter(annotation.name());
55+
io.github.resilience4j.ratelimiter.RateLimiter rateLimiter = registry.rateLimiter(annotation.name());
5656
if (rateLimiter == null) {
5757
return invocation.proceed();
5858
}

resilience4j-ratpack/src/main/java/io/github/resilience4j/ratpack/internal/RateLimiterProvider.java

Lines changed: 0 additions & 38 deletions
This file was deleted.

0 commit comments

Comments
 (0)