Micha Kops
www.hascode.com
1
Article on hasCode.com
Circuit Breakers for Java: Failsafe,
Javaslang-CB, Hystrix and Vert.x
Resilient Architecture in Practice
Micha Kops
www.hascode.com
2
Article on hasCode.com
Why?
● Remote-APIs might hang / have latency
issues / throw exceptions / behave
unresponsive
● Our application blocks resources, allocates
memory for threads and bound objects
● Spamming requests to an overloaded remote
API might prevent its recovery
Micha Kops
www.hascode.com
3
Article on hasCode.com
States
Micha Kops
www.hascode.com
4
Article on hasCode.com
Closed-State
● The circuit-breaker executes operations as
usual
● If a failure occurs, the circuit-breaker writes it
down
● If a specified error threshold (number of failures
or frequency of failures) is reached, it trips and
opens the circuit (transitions to the open-state)
Micha Kops
www.hascode.com
5
Article on hasCode.com
Open-State
● Calls to the circuit-breaker in the open state fail
immediately
● No call to the underlying operation is executed
● After a specified timeout is reached, the circuit-
breaker transitions to the half-open state.
Micha Kops
www.hascode.com
6
Article on hasCode.com
Half-Open-State
● In this state, one call is allowed to call the
underlying operation
● If this call fails, the circuit-breaker transitions to
the open-state again until another timeout is
reached
● If it succeeds, the circuit-breaker resets and
transitions to the closed-state.
Micha Kops
www.hascode.com
7
Article on hasCode.com
Implementations for Java
● Failsafe
● Javaslang-Circuitbreaker
● Netflix Hystrix
● Vert.x Circuitbreaker
Micha Kops
www.hascode.com
8
Article on hasCode.com
Failsafe - Example
UnstableApplication app = new UnstableApplication();
CircuitBreaker breaker = new CircuitBreaker().withFailureThreshold(2).withSuccessThreshold(5).withDelay(1,
TimeUnit.SECONDS);
RetryPolicy retryPolicy = new RetryPolicy().withDelay(2, TimeUnit.SECONDS).withMaxDuration(60,
TimeUnit.SECONDS)
.withBackoff(4, 40, TimeUnit.SECONDS);
System.out.printf("circuit-breaker state is: %sn", breaker.getState());
for (int i = 0; i < 10; i++) {
Thread.sleep(1000);
try {
String id = Failsafe.with(breaker).with(retryPolicy)
.onFailedAttempt((a, b) -> System.err.printf(
"failed with exception: '%s' at '%s', circuit-breaker state is: '%s'n", b,
ZonedDateTime.now(), breaker.getState()))
.onSuccess((a, b) -> System.out.printf("call succeeded, circuit-breaker state is: '%s'n",
breaker.getState()))
.get(app::generateId);
System.out.printf("FailsafeExample: id '%s' received at '%s'n", id, ZonedDateTime.now());
} catch (CircuitBreakerOpenException e) {
System.out.printf("circuit-breaker is open (state %s), time is '%s'n", breaker.getState(),
ZonedDateTime.now());
}
}
Micha Kops
www.hascode.com
9
Article on hasCode.com
Javaslang ExampleUnstableApplication app = new UnstableApplication();
CircuitBreakerConfig breakerConfig =
CircuitBreakerConfig.custom().ringBufferSizeInClosedState(2)
.ringBufferSizeInHalfOpenState(2).failureRateThreshold(50)
.waitDurationInOpenState(Duration.ofMillis(1000)).build();
CircuitBreaker breaker = CircuitBreaker.of("unstableAppBreaker",
breakerConfig);
Try.CheckedSupplier<String> decoratedSupplier =
Decorators.ofCheckedSupplier(app::generateId)
.withCircuitBreaker(breaker).decorate();
System.out.printf("circuit-breaker state is: %sn", breaker.getState());
for (int i = 0; i < 10; i++) {
Thread.sleep(1000);
Try<String> result = Try.of(decoratedSupplier)
.onSuccess((a) -> System.out.printf("call succeeded, circuit-
breaker state is: '%s'n",
breaker.getState()))
.onFailure(e -> System.err.printf(
"failed with exception: '%s' at '%s', circuit-breaker
state is: '%s'n", e,
ZonedDateTime.now(), breaker.getState()));
if (!result.isEmpty()) {
System.out.printf("JavaslangExample: id '%s' received at '%s'n",
result.get(), ZonedDateTime.now());
}
}
Micha Kops
www.hascode.com
10
Article on hasCode.com
Hystrix Example (I)
class IdGeneratingCommand extends HystrixObservableCommand<String> {
private final UnstableApplication app;
public IdGeneratingCommand(HystrixObservableCommand.Setter setter,
UnstableApplication app) {
super(setter);
this.app = app;
}
@Override
protected Observable<String> construct() {
return Observable.create(observer -> {
try {
if (!observer.isUnsubscribed()) {
observer.onNext(app.generateId());
observer.onCompleted();
}
} catch (SampleException e) {
observer.onError(e);
}
});
}
};
Micha Kops
www.hascode.com
11
Article on hasCode.com
Hystrix Example (II)UnstableApplication app = new UnstableApplication();
HystrixObservableCommand.Setter setter = HystrixObservableCommand.Setter
.withGroupKey(HystrixCommandGroupKey.Factory.asKey("unstableAppCmdGroup"))
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withCircuitBreakerEnabled(t
rue)
.withCircuitBreakerErrorThresholdPercentage(50)
.withCircuitBreakerSleepWindowInMilliseconds(1000).withCircuitBreakerRequestVolumeThreshold
(1));
for (int i = 0; i < 10; i++) {
CountDownLatch l = new CountDownLatch(1);
IdGeneratingCommand cmd = new IdGeneratingCommand(setter, app);
final HealthCounts healthCounts = cmd.getMetrics().getHealthCounts();
System.out.printf("circuit-breaker state is open: %s, %d errors of %d
requestsn",
cmd.isCircuitBreakerOpen(), healthCounts.getErrorCount(),
healthCounts.getTotalRequests());
Observable<String> observable = cmd.observe();
observable.subscribe(s -> {
System.out.printf("HystrixExample: id '%s' received at '%s'n", s,
ZonedDateTime.now());
} , t -> {
System.err.printf("HystrixExample: error %s, circuit-breaker state is open:
%sn", t,
cmd.isCircuitBreakerOpen());
} , () -> {
l.countDown();
});
l.await(4, TimeUnit.SECONDS);
}
Micha Kops
www.hascode.com
12
Article on hasCode.com
Vert.x ExampleUnstableApplication app = new UnstableApplication();
Vertx vertx = Vertx.vertx();
CircuitBreaker breaker = CircuitBreaker
.create("unstableAppBreaker", vertx,
new
CircuitBreakerOptions().setMaxFailures(2).setTimeout(2000).setFallbackOnFailure(true)
.setResetTimeout(2000))
.openHandler(h -> System.err.println("circuit-breaker opened"))
.closeHandler(h -> System.out.println("circuit-breaker closed"))
.halfOpenHandler(h -> System.err.println("circuit-breaker half-opened"));
System.out.printf("circuit-breaker state is: %sn", breaker.state());
for (int i = 0; i < 10; i++) {
Thread.sleep(1000);
breaker.<String> execute(future -> {
try {
final String id = app.generateId();
future.complete(id);
} catch (SampleException e) {
future.fail(e);
}
if (future.failed()) {
System.err.printf("failed with exception: '%s' at '%s', circuit-breaker
state is: '%s'n",
future.cause(), ZonedDateTime.now(), breaker.state());
}
}).setHandler(id -> {
if (id.succeeded())
System.out.printf("VertxExample: id '%s' received at '%s'n", id,
ZonedDateTime.now());
});
}
vertx.close();
Micha Kops
www.hascode.com
13
Article on hasCode.com
The End
Thanks for your audience

Circuit breakers for Java: Failsafe, Javaslang-Circuitbreaker, Hystrix and Vert.x

  • 1.
    Micha Kops www.hascode.com 1 Article onhasCode.com Circuit Breakers for Java: Failsafe, Javaslang-CB, Hystrix and Vert.x Resilient Architecture in Practice
  • 2.
    Micha Kops www.hascode.com 2 Article onhasCode.com Why? ● Remote-APIs might hang / have latency issues / throw exceptions / behave unresponsive ● Our application blocks resources, allocates memory for threads and bound objects ● Spamming requests to an overloaded remote API might prevent its recovery
  • 3.
  • 4.
    Micha Kops www.hascode.com 4 Article onhasCode.com Closed-State ● The circuit-breaker executes operations as usual ● If a failure occurs, the circuit-breaker writes it down ● If a specified error threshold (number of failures or frequency of failures) is reached, it trips and opens the circuit (transitions to the open-state)
  • 5.
    Micha Kops www.hascode.com 5 Article onhasCode.com Open-State ● Calls to the circuit-breaker in the open state fail immediately ● No call to the underlying operation is executed ● After a specified timeout is reached, the circuit- breaker transitions to the half-open state.
  • 6.
    Micha Kops www.hascode.com 6 Article onhasCode.com Half-Open-State ● In this state, one call is allowed to call the underlying operation ● If this call fails, the circuit-breaker transitions to the open-state again until another timeout is reached ● If it succeeds, the circuit-breaker resets and transitions to the closed-state.
  • 7.
    Micha Kops www.hascode.com 7 Article onhasCode.com Implementations for Java ● Failsafe ● Javaslang-Circuitbreaker ● Netflix Hystrix ● Vert.x Circuitbreaker
  • 8.
    Micha Kops www.hascode.com 8 Article onhasCode.com Failsafe - Example UnstableApplication app = new UnstableApplication(); CircuitBreaker breaker = new CircuitBreaker().withFailureThreshold(2).withSuccessThreshold(5).withDelay(1, TimeUnit.SECONDS); RetryPolicy retryPolicy = new RetryPolicy().withDelay(2, TimeUnit.SECONDS).withMaxDuration(60, TimeUnit.SECONDS) .withBackoff(4, 40, TimeUnit.SECONDS); System.out.printf("circuit-breaker state is: %sn", breaker.getState()); for (int i = 0; i < 10; i++) { Thread.sleep(1000); try { String id = Failsafe.with(breaker).with(retryPolicy) .onFailedAttempt((a, b) -> System.err.printf( "failed with exception: '%s' at '%s', circuit-breaker state is: '%s'n", b, ZonedDateTime.now(), breaker.getState())) .onSuccess((a, b) -> System.out.printf("call succeeded, circuit-breaker state is: '%s'n", breaker.getState())) .get(app::generateId); System.out.printf("FailsafeExample: id '%s' received at '%s'n", id, ZonedDateTime.now()); } catch (CircuitBreakerOpenException e) { System.out.printf("circuit-breaker is open (state %s), time is '%s'n", breaker.getState(), ZonedDateTime.now()); } }
  • 9.
    Micha Kops www.hascode.com 9 Article onhasCode.com Javaslang ExampleUnstableApplication app = new UnstableApplication(); CircuitBreakerConfig breakerConfig = CircuitBreakerConfig.custom().ringBufferSizeInClosedState(2) .ringBufferSizeInHalfOpenState(2).failureRateThreshold(50) .waitDurationInOpenState(Duration.ofMillis(1000)).build(); CircuitBreaker breaker = CircuitBreaker.of("unstableAppBreaker", breakerConfig); Try.CheckedSupplier<String> decoratedSupplier = Decorators.ofCheckedSupplier(app::generateId) .withCircuitBreaker(breaker).decorate(); System.out.printf("circuit-breaker state is: %sn", breaker.getState()); for (int i = 0; i < 10; i++) { Thread.sleep(1000); Try<String> result = Try.of(decoratedSupplier) .onSuccess((a) -> System.out.printf("call succeeded, circuit- breaker state is: '%s'n", breaker.getState())) .onFailure(e -> System.err.printf( "failed with exception: '%s' at '%s', circuit-breaker state is: '%s'n", e, ZonedDateTime.now(), breaker.getState())); if (!result.isEmpty()) { System.out.printf("JavaslangExample: id '%s' received at '%s'n", result.get(), ZonedDateTime.now()); } }
  • 10.
    Micha Kops www.hascode.com 10 Article onhasCode.com Hystrix Example (I) class IdGeneratingCommand extends HystrixObservableCommand<String> { private final UnstableApplication app; public IdGeneratingCommand(HystrixObservableCommand.Setter setter, UnstableApplication app) { super(setter); this.app = app; } @Override protected Observable<String> construct() { return Observable.create(observer -> { try { if (!observer.isUnsubscribed()) { observer.onNext(app.generateId()); observer.onCompleted(); } } catch (SampleException e) { observer.onError(e); } }); } };
  • 11.
    Micha Kops www.hascode.com 11 Article onhasCode.com Hystrix Example (II)UnstableApplication app = new UnstableApplication(); HystrixObservableCommand.Setter setter = HystrixObservableCommand.Setter .withGroupKey(HystrixCommandGroupKey.Factory.asKey("unstableAppCmdGroup")) .andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withCircuitBreakerEnabled(t rue) .withCircuitBreakerErrorThresholdPercentage(50) .withCircuitBreakerSleepWindowInMilliseconds(1000).withCircuitBreakerRequestVolumeThreshold (1)); for (int i = 0; i < 10; i++) { CountDownLatch l = new CountDownLatch(1); IdGeneratingCommand cmd = new IdGeneratingCommand(setter, app); final HealthCounts healthCounts = cmd.getMetrics().getHealthCounts(); System.out.printf("circuit-breaker state is open: %s, %d errors of %d requestsn", cmd.isCircuitBreakerOpen(), healthCounts.getErrorCount(), healthCounts.getTotalRequests()); Observable<String> observable = cmd.observe(); observable.subscribe(s -> { System.out.printf("HystrixExample: id '%s' received at '%s'n", s, ZonedDateTime.now()); } , t -> { System.err.printf("HystrixExample: error %s, circuit-breaker state is open: %sn", t, cmd.isCircuitBreakerOpen()); } , () -> { l.countDown(); }); l.await(4, TimeUnit.SECONDS); }
  • 12.
    Micha Kops www.hascode.com 12 Article onhasCode.com Vert.x ExampleUnstableApplication app = new UnstableApplication(); Vertx vertx = Vertx.vertx(); CircuitBreaker breaker = CircuitBreaker .create("unstableAppBreaker", vertx, new CircuitBreakerOptions().setMaxFailures(2).setTimeout(2000).setFallbackOnFailure(true) .setResetTimeout(2000)) .openHandler(h -> System.err.println("circuit-breaker opened")) .closeHandler(h -> System.out.println("circuit-breaker closed")) .halfOpenHandler(h -> System.err.println("circuit-breaker half-opened")); System.out.printf("circuit-breaker state is: %sn", breaker.state()); for (int i = 0; i < 10; i++) { Thread.sleep(1000); breaker.<String> execute(future -> { try { final String id = app.generateId(); future.complete(id); } catch (SampleException e) { future.fail(e); } if (future.failed()) { System.err.printf("failed with exception: '%s' at '%s', circuit-breaker state is: '%s'n", future.cause(), ZonedDateTime.now(), breaker.state()); } }).setHandler(id -> { if (id.succeeded()) System.out.printf("VertxExample: id '%s' received at '%s'n", id, ZonedDateTime.now()); }); } vertx.close();
  • 13.
    Micha Kops www.hascode.com 13 Article onhasCode.com The End Thanks for your audience