Skip to content

Commit dcf2ca3

Browse files
committed
Added CircuitBreaker post on failsafe
1 parent c831c26 commit dcf2ca3

File tree

4 files changed

+142
-8
lines changed

4 files changed

+142
-8
lines changed

stubbornjava-examples/src/main/java/com/stubbornjava/examples/failsafe/FailsafeWebserver.java

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ private static final void circuitClosed(HttpServerExchange exchange) {
7171
// {{end:handlers}}
7272

7373
// {{start:request}}
74-
private static void request(boolean error, boolean exception) {
74+
private static void request(String message, boolean error, boolean exception) {
7575
HttpUrl url = HttpUrl.parse("http://localhost:8080")
7676
.newBuilder()
7777
.addQueryParameter("error", String.valueOf(error))
@@ -80,7 +80,7 @@ private static void request(boolean error, boolean exception) {
8080

8181
Request request = new Request.Builder().get().url(url).build();
8282
try {
83-
log.info(HttpClient.globalClient().newCall(request).execute().body().string());
83+
log.info(message + " " + HttpClient.globalClient().newCall(request).execute().body().string());
8484
} catch (IOException e) {
8585
e.printStackTrace();
8686
}
@@ -101,28 +101,30 @@ public static void main(String[] args) {
101101
// Warm-up the circuit breaker it needs to hit at least max executions
102102
// Before it will reject anything. This will make that easier.
103103
for (int i = 0; i < 10; i++) {
104-
request(false, false);
104+
request("warmup", false, false);
105105
}
106106
ScheduledExecutorService schedExec = Executors.newScheduledThreadPool(1);
107107

108108
// A simple request that should always succeed
109-
schedExec.scheduleAtFixedRate(() -> request(false, false), 0, 500, TimeUnit.MILLISECONDS);
109+
schedExec.scheduleAtFixedRate(() -> request("ping", false, false), 0, 500, TimeUnit.MILLISECONDS);
110110

111111
// Send a batch of 15 bad requests to trigger the circuit breaker
112112
Runnable errors = () -> {
113-
log.info("Executing bad requests!");
113+
log.info("Start: Executing bad requests!");
114114
for (int i = 0; i < 15; i++) {
115-
request(true, false);
115+
request("bad request", true, false);
116116
}
117+
log.info("End: Executing bad requests!");
117118
};
118119
schedExec.schedule(errors, 1, TimeUnit.SECONDS);
119120

120121
// Send a batch of 15 requests that throw exceptions
121122
Runnable exceptions = () -> {
122-
log.info("Executing requests that throw exceptions!");
123+
log.info("Start: Executing requests that throw exceptions!");
123124
for (int i = 0; i < 15; i++) {
124-
request(false, true);
125+
request("exception request", false, true);
125126
}
127+
log.info("End: Executing requests that throw exceptions!");
126128
};
127129
schedExec.schedule(exceptions, 5, TimeUnit.SECONDS);
128130
}

stubbornjava-webapp/src/main/java/com/stubbornjava/webapp/post/PostData.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -760,6 +760,24 @@ public class PostData {
760760
))
761761
.build()
762762
);
763+
posts.add(PostRaw.builder()
764+
.postId(5L)
765+
.title("Increasing Resiliency with Circuit Breakers in your Undertow Webserver with Failsafe")
766+
.metaDesc("Utilize circuit breakers to fail fast and recover quickly with a CircuitBreakerHandler in Undertow. Shutoff misbehaving endpoints to allow other endpoints to proceede normally.")
767+
.dateCreated(LocalDateTime.parse("2018-02-05T01:15:30"))
768+
.dateUpdated(LocalDateTime.parse("2018-02-05T01:15:30"))
769+
.javaLibs(Lists.newArrayList(JavaLib.Undertow, JavaLib.Failsafe, JavaLib.OkHttp))
770+
.tags(Lists.newArrayList(Tags.WebServer, Tags.Resiliency))
771+
.gitFileReferences(Lists.newArrayList(
772+
FileReference.stubbornJava(
773+
"handler",
774+
"stubbornjava-common/src/main/java/com/stubbornjava/common/undertow/handlers/CircuitBreakerHandler.java")
775+
, FileReference.stubbornJava(
776+
"example",
777+
"stubbornjava-examples/src/main/java/com/stubbornjava/examples/failsafe/FailsafeWebserver.java")
778+
))
779+
.build()
780+
);
763781
}
764782

765783
public static List<PostRaw> getPosts() {

stubbornjava-webapp/src/main/java/com/stubbornjava/webapp/post/Tags.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ public class Tags {
3131
public static final Tag Ansible = addTag(new Tag(922794262770139008L, "Ansible"));
3232
public static final Tag Supervisord = addTag(new Tag(922794262770139008L, "Supervisord"));
3333
public static final Tag Security = addTag(new Tag(953801444178362856L, "Security"));
34+
public static final Tag Resiliency = addTag(new Tag(958330984838442254L, "Resiliency"));
3435

3536
private static Tag addTag(Tag tag) {
3637
TAGS.add(tag);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
<div class="anchored-md">
2+
{{#assign "markdown"}}
3+
It's inevitable that your system will have failures whether they are caused by bugs, network partitions, load, etc. What is important is being able to recover and recovering quickly. There have been some great resiliency libraries released in Java over the past few years. We found Netflix's [Hystrix](https://github.com/Netflix/Hystrix) to have a higher learning curve and a bit more complicated to use. We opted for [Failsafe](https://github.com/jhalterman/failsafe) which has more of an opt in model to only use what you want. We will outline how to circuit break your web server to help fail fast and recover quicker.
4+
5+
## What is a Circuit Breaker?
6+
The Wikipedia definition of a [circuit breaker](https://en.wikipedia.org/wiki/Circuit_breaker). "A circuit breaker is an automatically operated electrical switch designed to protect an electrical circuit from damage caused by overcurrent, typically resulting from an overload or short circuit. Its basic function is to interrupt current flow after a fault is detected. Unlike a fuse, which operates once and then must be replaced, a circuit breaker can be reset (either manually or automatically) to resume normal operation." In software we can think of this as a fail fast mechanism that will stop a code path once it notices a certain failure rate. This will hopefully give the system time to recover or at least allow other code paths to function while this one is down.
7+
8+
### Example Failsafe Circuit Breaker
9+
{{> templates/src/widgets/code/code-snippet file=example section=example.sections.breaker}}
10+
11+
## Circuit Breaker HttpHandler
12+
Let's utilize a `CircuitBreaker` to create a reusable `HttpHandler` that can circuit break based on a passed in `CircuitBreaker`. This could be useful if some resource pool is constrained and we want to help relieve some back-pressure by not sending any new requests. Another use case is potentially we have some bug such as forgetting to paginate a SQL query and just one specific endpoint is hanging non stop. Utilizing a `CircuitBreaker` we can automatically start shutting off individual endpoints or maybe an entire service as a whole using [middleware](/posts/logging-gzip-blocking-exception-handling-metrics-middleware-chaining-in-undertow). Keep in mind that techniques such as this can hurt you just as much as they help you if they are not configured well.
13+
14+
{{> templates/src/widgets/code/code-snippet file=handler section=handler.sections.handler}}
15+
16+
## Example Handlers
17+
Here we have a `HttpHandler` that we can easily mimic some errors in as well as a `HttpHander` that returns a 500 - server error.
18+
19+
{{> templates/src/widgets/code/code-snippet file=example section=example.sections.handlers}}
20+
21+
## Making some Requests
22+
Here is a quick little method to use [OkHttp](/posts/okhttp-example-rest-client) to send a HTTP request to our example server.
23+
24+
{{> templates/src/widgets/code/code-snippet file=example section=example.sections.request}}
25+
26+
## Example Server
27+
Finally we can start up a server and send some requests at it with a `ScheduledExecutorService`.
28+
29+
{{> templates/src/widgets/code/code-snippet file=example section=example.sections.main}}
30+
31+
### Output
32+
<pre class="line-numbers"><code class="language-bash">2018-02-05 23:43:16.168 [main] INFO c.s.common.undertow.SimpleServer - ListenerInfo{protcol='http', address=/0:0:0:0:0:0:0:0:8080, sslContext=null}
33+
2018-02-05 23:43:16.542 [main] INFO c.s.e.failsafe.FailsafeWebserver - warmup Circuit is open everything is functioning properly.
34+
2018-02-05 23:43:16.549 [main] INFO c.s.e.failsafe.FailsafeWebserver - warmup Circuit is open everything is functioning properly.
35+
2018-02-05 23:43:16.553 [main] INFO c.s.e.failsafe.FailsafeWebserver - warmup Circuit is open everything is functioning properly.
36+
2018-02-05 23:43:16.554 [main] INFO c.s.e.failsafe.FailsafeWebserver - warmup Circuit is open everything is functioning properly.
37+
2018-02-05 23:43:16.556 [main] INFO c.s.e.failsafe.FailsafeWebserver - warmup Circuit is open everything is functioning properly.
38+
2018-02-05 23:43:16.557 [main] INFO c.s.e.failsafe.FailsafeWebserver - warmup Circuit is open everything is functioning properly.
39+
2018-02-05 23:43:16.559 [main] INFO c.s.e.failsafe.FailsafeWebserver - warmup Circuit is open everything is functioning properly.
40+
2018-02-05 23:43:16.561 [main] INFO c.s.e.failsafe.FailsafeWebserver - warmup Circuit is open everything is functioning properly.
41+
2018-02-05 23:43:16.562 [main] INFO c.s.e.failsafe.FailsafeWebserver - warmup Circuit is open everything is functioning properly.
42+
2018-02-05 23:43:16.564 [main] INFO c.s.e.failsafe.FailsafeWebserver - warmup Circuit is open everything is functioning properly.
43+
2018-02-05 23:43:16.568 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - ping Circuit is open everything is functioning properly.
44+
2018-02-05 23:43:17.068 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - ping Circuit is open everything is functioning properly.
45+
2018-02-05 23:43:17.568 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - ping Circuit is open everything is functioning properly.
46+
2018-02-05 23:43:17.568 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - Start: Executing bad requests!
47+
2018-02-05 23:43:17.569 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - bad request Bad Request
48+
2018-02-05 23:43:17.570 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - bad request Bad Request
49+
2018-02-05 23:43:17.572 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - bad request Bad Request
50+
2018-02-05 23:43:17.574 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - bad request Bad Request
51+
2018-02-05 23:43:17.575 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - bad request Bad Request
52+
2018-02-05 23:43:17.576 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - bad request Bad Request
53+
2018-02-05 23:43:17.577 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - bad request Bad Request
54+
2018-02-05 23:43:17.578 [XNIO-1 I/O-2] INFO c.s.e.failsafe.FailsafeWebserver - Circuit Opened
55+
2018-02-05 23:43:17.580 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - bad request 500 - Internal Server Error
56+
2018-02-05 23:43:17.581 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - bad request 500 - Internal Server Error
57+
2018-02-05 23:43:17.583 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - bad request 500 - Internal Server Error
58+
2018-02-05 23:43:17.584 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - bad request 500 - Internal Server Error
59+
2018-02-05 23:43:17.585 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - bad request 500 - Internal Server Error
60+
2018-02-05 23:43:17.587 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - bad request 500 - Internal Server Error
61+
2018-02-05 23:43:17.588 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - bad request 500 - Internal Server Error
62+
2018-02-05 23:43:17.589 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - bad request 500 - Internal Server Error
63+
2018-02-05 23:43:17.589 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - End: Executing bad requests!
64+
2018-02-05 23:43:18.070 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - ping 500 - Internal Server Error
65+
2018-02-05 23:43:18.568 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - ping 500 - Internal Server Error
66+
2018-02-05 23:43:19.068 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - ping 500 - Internal Server Error
67+
2018-02-05 23:43:19.570 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - ping 500 - Internal Server Error
68+
2018-02-05 23:43:20.070 [XNIO-1 I/O-2] INFO c.s.e.failsafe.FailsafeWebserver - Circuit Half-Open
69+
2018-02-05 23:43:20.071 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - ping Circuit is open everything is functioning properly.
70+
2018-02-05 23:43:20.573 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - ping Circuit is open everything is functioning properly.
71+
2018-02-05 23:43:21.068 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - ping Circuit is open everything is functioning properly.
72+
2018-02-05 23:43:21.569 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - ping Circuit is open everything is functioning properly.
73+
2018-02-05 23:43:21.570 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - Start: Executing requests that throw exceptions!
74+
2018-02-05 23:43:21.571 [XNIO-1 I/O-2] INFO c.s.e.failsafe.FailsafeWebserver - Circuit Closed
75+
2018-02-05 23:43:21.572 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - exception request 500 - Internal Server Error
76+
2018-02-05 23:43:21.574 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - exception request 500 - Internal Server Error
77+
2018-02-05 23:43:21.575 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - exception request 500 - Internal Server Error
78+
2018-02-05 23:43:21.576 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - exception request 500 - Internal Server Error
79+
2018-02-05 23:43:21.578 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - exception request 500 - Internal Server Error
80+
2018-02-05 23:43:21.579 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - exception request 500 - Internal Server Error
81+
2018-02-05 23:43:21.581 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - exception request 500 - Internal Server Error
82+
2018-02-05 23:43:21.583 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - exception request 500 - Internal Server Error
83+
2018-02-05 23:43:21.584 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - exception request 500 - Internal Server Error
84+
2018-02-05 23:43:21.585 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - exception request 500 - Internal Server Error
85+
2018-02-05 23:43:21.586 [XNIO-1 I/O-2] INFO c.s.e.failsafe.FailsafeWebserver - Circuit Opened
86+
2018-02-05 23:43:21.587 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - exception request 500 - Internal Server Error
87+
2018-02-05 23:43:21.587 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - exception request 500 - Internal Server Error
88+
2018-02-05 23:43:21.589 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - exception request 500 - Internal Server Error
89+
2018-02-05 23:43:21.590 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - exception request 500 - Internal Server Error
90+
2018-02-05 23:43:21.591 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - exception request 500 - Internal Server Error
91+
2018-02-05 23:43:21.591 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - End: Executing requests that throw exceptions!
92+
2018-02-05 23:43:22.071 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - ping 500 - Internal Server Error
93+
2018-02-05 23:43:22.572 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - ping 500 - Internal Server Error
94+
2018-02-05 23:43:23.072 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - ping 500 - Internal Server Error
95+
2018-02-05 23:43:23.573 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - ping 500 - Internal Server Error
96+
2018-02-05 23:43:24.068 [XNIO-1 I/O-2] INFO c.s.e.failsafe.FailsafeWebserver - Circuit Half-Open
97+
2018-02-05 23:43:24.069 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - ping Circuit is open everything is functioning properly.
98+
2018-02-05 23:43:24.573 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - ping Circuit is open everything is functioning properly.
99+
2018-02-05 23:43:25.069 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - ping Circuit is open everything is functioning properly.
100+
2018-02-05 23:43:25.572 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - ping Circuit is open everything is functioning properly.
101+
2018-02-05 23:43:26.068 [XNIO-1 I/O-2] INFO c.s.e.failsafe.FailsafeWebserver - Circuit Closed
102+
2018-02-05 23:43:26.069 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - ping Circuit is open everything is functioning properly.
103+
2018-02-05 23:43:26.569 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - ping Circuit is open everything is functioning properly.
104+
2018-02-05 23:43:27.069 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - ping Circuit is open everything is functioning properly.
105+
2018-02-05 23:43:27.570 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - ping Circuit is open everything is functioning properly.
106+
2018-02-05 23:43:28.073 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - ping Circuit is open everything is functioning properly.
107+
2018-02-05 23:43:28.572 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - ping Circuit is open everything is functioning properly.
108+
2018-02-05 23:43:29.072 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - ping Circuit is open everything is functioning properly.
109+
2018-02-05 23:43:29.569 [pool-1-thread-1] INFO c.s.e.failsafe.FailsafeWebserver - ping Circuit is open everything is functioning properly.</code></pre>
110+
111+
{{/assign}}
112+
{{md markdown}}
113+
</div>

0 commit comments

Comments
 (0)