Skip to content

Commit eabff55

Browse files
Dan MaasRobWin
Dan Maas
authored andcommitted
Issue ReactiveX#126: Feature ratpack events
* check * adding streaming * checkpoint on ratelimiter events * added ratelimiter event endpoint tests * added retry events * configurable
1 parent 4e9ddc3 commit eabff55

22 files changed

+1926
-33
lines changed

resilience4j-documentation/src/docs/asciidoc/addon_guides/ratpack.adoc

Lines changed: 192 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -340,16 +340,199 @@ public class MyModule extends AbstractModule {
340340
}
341341
----
342342

343+
==== Event Monitoring
343344

345+
===== CircuitBreaker
346+
347+
The emitted CircuitBreaker events are stored in a separate circular event consumer buffers. The size of a event consumer buffer can be configured per CircuitBreaker in the application.yml file (eventConsumerBufferSize).
348+
The demo adds a custom Ratpack actuator endpoint which can be used to monitor the emitted events of your CircuitBreakers.
349+
The endpoint `/circuitbreaker` lists the names of all CircuitBreaker instances.
350+
For example:
351+
352+
----
353+
{
354+
"circuitBreakers": [
355+
"backendA",
356+
"backendB"
357+
]
358+
}
359+
----
344360

345-
==== Monitoring
346-
TODO
347-
Ratpack provides the concept of a health check. See https://ratpack.io/manual/current/api/ratpack/health/HealthCheckHandler.html for details.
348-
CircuitBreaker, RateLimiter, and Retry health checks have not been implemented yet.
349-
When implemented they should function similarly to the spring boot health checks.
361+
The endpoint `/circuitbreaker/events` lists the latest 100 emitted events of all CircuitBreaker instances.
362+
The endpoint `/circuitbreaker/stream/events` streams emitted events of all CircuitBreaker instances using Server-Sent Events.
350363

351-
==== CircuitBreaker Event Monitoring
352-
TODO
353-
Handlers for displaying the last X CircuitBreaker, Ratelimiter, or Retry events are not yet implemented.
354-
When implemented they should function similarly to the spring boot management endpoints.
364+
----
365+
{
366+
"circuitBreakerEvents":[
367+
{
368+
"circuitBreakerName": "backendA",
369+
"type": "ERROR",
370+
"creationTime": "2017-01-10T15:39:17.117+01:00[Europe/Berlin]",
371+
"errorMessage": "org.springframework.web.client.HttpServerErrorException: 500 This is a remote exception",
372+
"durationInMs": 0
373+
},
374+
{
375+
"circuitBreakerName": "backendA",
376+
"type": "SUCCESS",
377+
"creationTime": "2017-01-10T15:39:20.518+01:00[Europe/Berlin]",
378+
"durationInMs": 0
379+
},
380+
{
381+
"circuitBreakerName": "backendB",
382+
"type": "ERROR",
383+
"creationTime": "2017-01-10T15:41:31.159+01:00[Europe/Berlin]",
384+
"errorMessage": "org.springframework.web.client.HttpServerErrorException: 500 This is a remote exception",
385+
"durationInMs": 0
386+
},
387+
{
388+
"circuitBreakerName": "backendB",
389+
"type": "SUCCESS",
390+
"creationTime": "2017-01-10T15:41:33.526+01:00[Europe/Berlin]",
391+
"durationInMs": 0
392+
}
393+
]
394+
}
395+
----
355396

397+
The endpoint `/circuitbreaker/events/{circuitBreakerName}` lists the latest emitted events of a specific CircuitBreaker.
398+
The endpoint `/circuitbreaker/stream/events/{circuitBreakerName}` streams emitted events using Server-Sent Events.
399+
For example `/circuitbreaker/events/backendA`:
400+
401+
----
402+
{
403+
"circuitBreakerEvents":[
404+
{
405+
"circuitBreakerName": "backendA",
406+
"type": "ERROR",
407+
"creationTime": "2017-01-10T15:39:17.117+01:00[Europe/Berlin]",
408+
"errorMessage": "org.springframework.web.client.HttpServerErrorException: 500 This is a remote exception",
409+
"durationInMs": 0
410+
},
411+
{
412+
"circuitBreakerName": "backendA",
413+
"type": "SUCCESS",
414+
"creationTime": "2017-01-10T15:39:20.518+01:00[Europe/Berlin]",
415+
"durationInMs": 0
416+
},
417+
{
418+
"circuitBreakerName": "backendA",
419+
"type": "STATE_TRANSITION",
420+
"creationTime": "2017-01-10T15:39:22.341+01:00[Europe/Berlin]",
421+
"stateTransition": "CLOSED_TO_OPEN"
422+
},
423+
{
424+
"circuitBreakerName": "backendA",
425+
"type": "NOT_PERMITTED",
426+
"creationTime": "2017-01-10T15:39:22.780+01:00[Europe/Berlin]"
427+
}
428+
]
429+
}
430+
----
431+
432+
You can even filter the list of events.
433+
The endpoint `/circuitbreaker/events/{circuitBreakerName}/{eventType}` lists the filtered events.
434+
The endpoint `/circuitbreaker/stream/events/{circuitBreakerName}/{eventType}` streams emitted events using Server-Sent Events.
435+
Event types can be:
436+
437+
* ERROR: A CircuitBreakerEvent which informs that an error has been recorded.
438+
* IGNORED_ERROR: A CircuitBreakerEvent which informs that an error has been ignored.
439+
* SUCCESS: A CircuitBreakerEvent which informs that a success has been recorded.
440+
* NOT_PERMITTED: A CircuitBreakerEvent which informs that a call was not permitted because the CircuitBreaker state is OPEN.
441+
* STATE_TRANSITION: A CircuitBreakerEvent which informs the state of the CircuitBreaker has been changed.
442+
443+
For example /circuitbreaker/events/backendA/ERROR`:
444+
----
445+
{
446+
"circuitBreakerEvents":[
447+
{
448+
"circuitBreakerName": "backendA",
449+
"type": "ERROR",
450+
"creationTime": "2017-01-10T15:42:59.324+01:00[Europe/Berlin]",
451+
"errorMessage": "org.springframework.web.client.HttpServerErrorException: 500 This is a remote exception",
452+
"durationInMs": 0
453+
},
454+
{
455+
"circuitBreakerName": "backendA",
456+
"type": "ERROR",
457+
"creationTime": "2017-01-10T15:43:22.802+01:00[Europe/Berlin]",
458+
"errorMessage": "org.springframework.web.client.HttpServerErrorException: 500 This is a remote exception",
459+
"durationInMs": 0
460+
}
461+
]
462+
}
463+
----
464+
465+
===== RateLimiter
466+
These are the same endpoints as implemented for CircuitBreaker,
467+
so for detailed documentation please refer to previous section.
468+
469+
List of available endpoints:
470+
471+
* `/ratelimiter/events`
472+
* `/ratelimiter/stream/events`
473+
* `/ratelimiter/events/{retryName}`
474+
* `/ratelimiter/stream/events/{retryName}`
475+
* `/ratelimiter/events/{retryName}/{eventType}`
476+
* `/ratelimiter/stream/events/{retryName}/{eventType}`
477+
478+
Example of response:
479+
----
480+
{
481+
"rateLimiterEvents": [
482+
{
483+
"rateLimiterName": "backendA",
484+
"rateLimiterEventType": "SUCCESSFUL_ACQUIRE",
485+
"rateLimiterCreationTime": "2017-05-05T21:29:40.463+03:00[Europe/Uzhgorod]"
486+
},
487+
{
488+
"rateLimiterName": "backendA",
489+
"rateLimiterEventType": "SUCCESSFUL_ACQUIRE",
490+
"rateLimiterCreationTime": "2017-05-05T21:29:40.469+03:00[Europe/Uzhgorod]"
491+
},
492+
{
493+
"rateLimiterName": "backendA",
494+
"rateLimiterEventType": "FAILED_ACQUIRE",
495+
"rateLimiterCreationTime": "2017-05-05T21:29:41.268+03:00[Europe/Uzhgorod]"
496+
}
497+
]
498+
}
499+
----
500+
501+
===== Retry
502+
These are the same endpoints as implemented for CircuitBreaker,
503+
so for detailed documentation please refer to previous sections.
504+
505+
List of available endpoints:
506+
507+
* `/retry/events`
508+
* `/retry/stream/events`
509+
* `/retry/events/{retryName}`
510+
* `/retry/stream/events/{retryName}`
511+
* `/retry/events/{retryName}/{eventType}`
512+
* `/retry/stream/events/{retryName}/{eventType}`
513+
514+
Example of response:
515+
----
516+
{
517+
"retryEvents": [
518+
{
519+
"retryName": "backendA",
520+
"retryEventType": "ERROR",
521+
"numberOfRetryAttempts":3,
522+
"retryCreationTime": "2017-05-05T21:29:40.463+03:00[Europe/Uzhgorod]"
523+
},
524+
{
525+
"retryName": "backendA",
526+
"retryEventType": "ERROR",
527+
"numberOfRetryAttempts":3,
528+
"retryCreationTime": "2017-05-05T21:29:40.469+03:00[Europe/Uzhgorod]"
529+
},
530+
{
531+
"retryName": "backendA",
532+
"retryEventType": "ERROR",
533+
"numberOfRetryAttempts":3,
534+
"retryCreationTime": "2017-05-05T21:29:41.268+03:00[Europe/Uzhgorod]"
535+
}
536+
]
537+
}
538+
----

resilience4j-ratpack/build.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ dependencies {
55
compile project(':resilience4j-circuitbreaker')
66
compile project(':resilience4j-ratelimiter')
77
compile project(':resilience4j-retry')
8+
compile project(':resilience4j-consumer')
89
compileOnly ( libraries.ratpack_metrics )
910
compileOnly project(':resilience4j-prometheus')
1011
compileOnly project(':resilience4j-metrics')
@@ -16,5 +17,5 @@ dependencies {
1617
}
1718

1819
test {
19-
maxParallelForks = 8
20+
maxParallelForks = 1
2021
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/*
2+
* Copyright 2017 Dan Maas
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.github.resilience4j.ratpack;
18+
19+
import ratpack.func.Function;
20+
21+
import static ratpack.util.Exceptions.uncheck;
22+
23+
public class EndpointsConfig {
24+
25+
private EndpointConfig circuitBreakers = new EndpointConfig("circuitbreaker");
26+
private EndpointConfig rateLimiters = new EndpointConfig("ratelimiter");
27+
private EndpointConfig retries = new EndpointConfig("retry");
28+
29+
public EndpointConfig getCircuitBreakers() {
30+
return circuitBreakers;
31+
}
32+
33+
public EndpointsConfig circuitBreakers(Function<? super EndpointConfig, ? extends EndpointConfig> configure) {
34+
try {
35+
circuitBreakers = configure.apply(new EndpointConfig("circuitbreaker"));
36+
return this;
37+
} catch (Exception e) {
38+
throw uncheck(e);
39+
}
40+
}
41+
42+
public EndpointConfig getRateLimiters() {
43+
return rateLimiters;
44+
}
45+
46+
public EndpointsConfig rateLimiters(Function<? super EndpointConfig, ? extends EndpointConfig> configure) {
47+
try {
48+
rateLimiters = configure.apply(new EndpointConfig("ratelimiter"));
49+
return this;
50+
} catch (Exception e) {
51+
throw uncheck(e);
52+
}
53+
}
54+
55+
public EndpointConfig getRetries() {
56+
return retries;
57+
}
58+
59+
public EndpointsConfig retries(Function<? super EndpointConfig, ? extends EndpointConfig> configure) {
60+
try {
61+
retries = configure.apply(new EndpointConfig("retry"));
62+
return this;
63+
} catch (Exception e) {
64+
throw uncheck(e);
65+
}
66+
}
67+
68+
public static class EndpointConfig {
69+
private boolean enabled = true;
70+
private String path;
71+
private int eventConsumerBufferSize = 100;
72+
73+
public EndpointConfig() {
74+
}
75+
76+
public EndpointConfig(String path) {
77+
this.path = path;
78+
}
79+
80+
public boolean isEnabled() {
81+
return enabled;
82+
}
83+
84+
public EndpointConfig enabled(boolean enabled) {
85+
this.enabled = enabled;
86+
return this;
87+
}
88+
89+
public String getPath() {
90+
return path;
91+
}
92+
93+
public EndpointConfig path(String path) {
94+
this.path = path;
95+
return this;
96+
}
97+
98+
public int getEventConsumerBufferSize() {
99+
return eventConsumerBufferSize;
100+
}
101+
102+
public EndpointConfig eventConsumerBufferSize(int eventConsumerBufferSize) {
103+
this.eventConsumerBufferSize = eventConsumerBufferSize;
104+
return this;
105+
}
106+
}
107+
}

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ public class Resilience4jConfig {
3232
private Map<String, RetryConfig> retries = new HashMap<>();
3333
private boolean metrics = false;
3434
private boolean prometheus = false;
35+
private EndpointsConfig endpoints = new EndpointsConfig();
3536

3637
public Resilience4jConfig circuitBreaker(String name, Function<? super CircuitBreakerConfig, ? extends CircuitBreakerConfig> configure) {
3738
try {
@@ -73,6 +74,15 @@ public Resilience4jConfig prometheus(boolean prometheus) {
7374
return this;
7475
}
7576

77+
public Resilience4jConfig endpoints(Function<? super EndpointsConfig, ? extends EndpointsConfig> configure) {
78+
try {
79+
endpoints = configure.apply(new EndpointsConfig());
80+
return this;
81+
} catch (Exception e) {
82+
throw uncheck(e);
83+
}
84+
}
85+
7686
public Map<String, CircuitBreakerConfig> getCircuitBreakers() {
7787
return circuitBreakers;
7888
}
@@ -92,4 +102,8 @@ public boolean isMetrics() {
92102
public boolean isPrometheus() {
93103
return prometheus;
94104
}
105+
106+
public EndpointsConfig getEndpoints() {
107+
return endpoints;
108+
}
95109
}

0 commit comments

Comments
 (0)