Resilience with Hystrix

Uwe Friedrichsen
Uwe Friedrichsencodecentric AG
Resilience with Hystrix
An introduction

Uwe Friedrichsen, codecentric AG, 2014
@ufried
Uwe Friedrichsen | uwe.friedrichsen@codecentric.de | http://slideshare.net/ufried | http://ufried.tumblr.com
It‘s all about production!
Production
Availability
Resilience
Fault Tolerance
re•sil•ience (rɪˈzɪl yəns) also re•sil′ien•cy, n.

1.  the power or ability to return to the original form, position,
etc., after being bent, compressed, or stretched; elasticity.
2.  ability to recover readily from illness, depression, adversity,
or the like; buoyancy.

Random House Kernerman Webster's College Dictionary, © 2010 K Dictionaries Ltd.
Copyright 2005, 1997, 1991 by Random House, Inc. All rights reserved.


http://www.thefreedictionary.com/resilience
Resilience with Hystrix
Implemented patterns






•  Timeout
•  Circuit breaker
•  Load shedder
Supported patterns

•  Bulkheads

(a.k.a. Failure Units)
•  Fail fast
•  Fail silently
•  Graceful degradation of service
•  Failover
•  Escalation
•  Retry
•  ...
That‘s been enough theory
Give us some code – now!
Basics
Hello, world!
public class HelloCommand extends HystrixCommand<String> {
private static final String COMMAND_GROUP = "default";
private final String name;
public HelloCommand(String name) {
super(HystrixCommandGroupKey.Factory.asKey(COMMAND_GROUP));
this.name = name;
}
@Override
protected String run() throws Exception {
return "Hello, " + name;
}
}
@Test
public void shouldGreetWorld() {
String result = new HelloCommand("World").execute();
assertEquals("Hello, World", result);
}
Synchronous execution
@Test
public void shouldExecuteSynchronously() {
String s = new HelloCommand("Bob").execute();
assertEquals("Hello, Bob", s);
}
Asynchronous execution
@Test
public void shouldExecuteAsynchronously() {
Future<String> f = new HelloCommand("Alice").queue();
String s = null;
try {
s = f.get();
} catch (InterruptedException | ExecutionException e) {
// Handle Future.get() exceptions here
}
assertEquals("Hello, Alice", s);
}
Reactive execution (simple)
@Test
public void shouldExecuteReactiveSimple() {
Observable<String> observable =
new HelloCommand("Alice").observe();
String s = observable.toBlockingObservable().single();
assertEquals("Hello, Alice", s);
}
Reactive execution (full)
public class CommandHelloObserver implements Observer<String> {
// Needed for communication between observer and test case
private final AtomicReference<String> aRef;
private final Semaphore semaphore;
public CommandHelloObserver(AtomicReference<String> aRef,
Semaphore semaphore) {
this.aRef = aRef;
this.semaphore = semaphore;
}
@Override
public void onCompleted() { // Not needed here }
@Override
public void onError(Throwable e) { // Not needed here }
@Override
public void onNext(String s) {
aRef.set(s);
semaphore.release();
}
}
@Test
public void shouldExecuteReactiveFull() {
// Needed for communication between observer and test case
AtomicReference<String> aRef = new AtomicReference<>();
Semaphore semaphore = new Semaphore(0);
Observable<String> observable = new HelloCommand("Bob").observe();
Observer<String> observer =
new CommandHelloObserver(aRef, semaphore);
observable.subscribe(observer);
// Wait until observer received a result
try {
semaphore.acquire();
} catch (InterruptedException e) {
// Handle exceptions here
}
String s = aRef.get();
assertEquals("Hello, Bob", s);
}
Fallback
public class FallbackCommand extends HystrixCommand<String> {
private static final String COMMAND_GROUP = "default";
public FallbackCommand() {
super(HystrixCommandGroupKey.Factory.asKey(COMMAND_GROUP));
}
@Override
protected String run() throws Exception {
throw new RuntimeException("I will always fail");
}
@Override
protected String getFallback() {
return "Powered by fallback";
}
}
@Test
public void shouldGetFallbackResponse() {
String s = new FallbackCommand().execute();
assertEquals("Powered by fallback", s);
}
Error propagation
public class ErrorPropagationCommand extends HystrixCommand<String> {
private static final String COMMAND_GROUP = "default";
protected ErrorPropagationCommand() {
super(HystrixCommandGroupKey.Factory.asKey(COMMAND_GROUP));
}
@Override
protected String run() throws Exception {
throw new HystrixBadRequestException("I fail differently",
new RuntimeException("I will always fail"));
}
@Override
protected String getFallback() {
return "Powered by fallback";
}
}
@Test
public void shouldGetFallbackResponse() {
String s = null;
try {
s = new ErrorPropagationCommand().execute();
fail(); // Just to make sure
} catch (HystrixBadRequestException e) {
assertEquals("I will fail differently", e.getMessage());
assertEquals("I will always fail", e.getCause().getMessage());
}
assertNull(s); // Fallback is not triggered
}
How it works
Source: https://github.com/Netflix/Hystrix/wiki/How-it-Works
Source: https://github.com/Netflix/Hystrix/wiki/How-it-Works
Source: https://github.com/Netflix/Hystrix/wiki/How-it-Works
Configuration
Configuration

•  Based on Archaius by Netflix

which extends the Apache Commons Configuration Library
•  Four levels of precedence
1.  Global default from code
2.  Dynamic global default property
3.  Instance default from code
4.  Dynamic instance property

Provides many configuration & tuning options
Configuration – Some examples

•  hystrix.command.*.execution.isolation.strategy

Either “THREAD” or “SEMAPHORE” (Default: THREAD)
•  hystrix.command.*.execution.isolation.thread.timeoutInMilliseconds

Time to wait for the run() method to complete (Default: 1000)
•  h.c.*.execution.isolation.semaphore.maxConcurrentRequests

Maximum number of concurrent requests when using semaphores (Default: 10)
•  hystrix.command.*.circuitBreaker.errorThresholdPercentage

Error percentage at which the breaker trips open (Default: 50)
•  hystrix.command.*.circuitBreaker.sleepWindowInMilliseconds

Time to wait before attempting to reset the breaker after tripping (Default: 5000)
* must be either “default” or the command key name
Configuration – More examples

•  hystrix.threadpool.*.coreSize

Maximum number of concurrent requests when using thread pools (Default: 10)
•  hystrix.threadpool.*.maxQueueSize

Maximum LinkedBlockingQueue size - -1 for using SynchronousQueue (Default: -1)
•  hystrix.threadpool.default.queueSizeRejectionThreshold

Queue size rejection threshold (Default: 5)

… and many more
* must be either “default” or the thread pool key name
Patterns
Timeout
public class LatentResource {
private final long latency;
public LatentResource(long latency) {
this.latency = ((latency < 0L) ? 0L : latency);
}
public String getData() {
addLatency(); // This is the important part
return "Some value”;
}
private void addLatency() {
try {
Thread.sleep(latency);
} catch (InterruptedException e) {
// We do not care about this here
}
}
}
public class TimeoutCommand extends HystrixCommand<String> {
private static final String COMMAND_GROUP = "default";
private final LatentResource resource;
public TimeoutCommand(int timeout, LatentResource resource) {
super(Setter.withGroupKey(
HystrixCommandGroupKey.Factory.asKey(COMMAND_GROUP))
.andCommandPropertiesDefaults(
HystrixCommandProperties.Setter()
.withExecutionIsolationThreadTimeoutInMilliseconds(
timeout)));
this.resource = resource;
}
@Override
protected String run() throws Exception {
return resource.getData();
}
@Override
protected String getFallback() {
return "Resource timed out";
}
}
@Test
public void shouldGetNormalResponse() {
LatentResource resource = new LatentResource(50L);
TimeoutCommand command = new TimeoutCommand(100, resource);
String s = command.execute();
assertEquals("Some value", s);
}
@Test
public void shouldGetFallbackResponse() {
LatentResource resource = new LatentResource(150L);
TimeoutCommand command = new TimeoutCommand(100, resource);
String s = command.execute();
assertEquals("Resource timed out", s);
}
Circuit breaker
public class CircuitBreakerCommand extends HystrixCommand<String> {
private static final String COMMAND_GROUP = "default";
public CircuitBreakerCommand(String name, boolean open) {
super(Setter.withGroupKey(
HystrixCommandGroupKey.Factory.asKey(COMMAND_GROUP))
.andCommandKey(HystrixCommandKey.Factory.asKey(name))
.andCommandPropertiesDefaults(
HystrixCommandProperties.Setter()
.withCircuitBreakerForceOpen(open)));
}
@Override
protected String run() throws Exception {
return("Some result");
}
@Override
protected String getFallback() {
return "Fallback response";
}
}
@Test
public void shouldExecuteWithCircuitBreakerClosed() {
CircuitBreakerCommand command = new
CircuitBreakerCommand("ClosedBreaker", false);
String s = command.execute();
assertEquals("Some result", s);
HystrixCircuitBreaker breaker =
HystrixCircuitBreaker.Factory
.getInstance(command.getCommandKey());
assertTrue(breaker.allowRequest());
}
@Test
public void shouldExecuteWithCircuitBreakerOpen() {
CircuitBreakerCommand command = new
CircuitBreakerCommand("OpenBreaker", true);
String s = command.execute();
assertEquals("Fallback response", s);
HystrixCircuitBreaker breaker =
HystrixCircuitBreaker.Factory
.getInstance(command.getCommandKey());
assertFalse(breaker.allowRequest());
}
Load shedder (Thread pool)
public class LatentCommand extends HystrixCommand<String> {
private static final String COMMAND_GROUP = "default";
private final LatentResource resource;
public LatentCommand(LatentResource resource) {
super(HystrixCommandGroupKey.Factory.asKey(COMMAND_GROUP));
this.resource = resource;
}
@Override
protected String run() throws Exception {
return resource.getData();
}
@Override
protected String getFallback() {
return "Fallback triggered";
}
}
@Test
public void shouldShedLoad() {
List<Future<String>> l = new LinkedList<>();
LatentResource resource = new LatentResource(500L); // Make latent
// Use up all available threads
for (int i = 0; i < 10; i++)
l.add(new LatentCommand(resource).queue());
// Call will be rejected as thread pool is exhausted
String s = new LatentCommand(resource).execute();
assertEquals("Fallback triggered", s);
// All other calls succeed
for (Future<String> f : l)
assertEquals("Some value", get(f)); // wrapper for f.get()
}
Load shedder (Semaphore)
public class SemaphoreCommand extends HystrixCommand<String> {
private static final String COMMAND_GROUP = "default";
private final LatentResource resource;
public SemaphoreCommand(LatentResource resource) {
super(Setter.withGroupKey(
HystrixCommandGroupKey.Factory.asKey(COMMAND_GROUP))
.andCommandPropertiesDefaults(
HystrixCommandProperties.Setter()
.withExecutionIsolationStrategy(HystrixCommandProperties
.ExecutionIsolationStrategy.SEMAPHORE)));
this.resource = resource;
}
@Override
protected String run() throws Exception {
return resource.getData();
}
@Override
protected String getFallback() {
return "Fallback triggered";
}
}
private class SemaphoreCommandInvocation implements
java.util.concurrent.Callable<String> {
private final LatentResource resource;
public SemaphoreCommandInvocation(LatentResource resource) {
this.resource = resource;
}
@Override
public String call() throws Exception {
return new SemaphoreCommand(resource).execute();
}
}
@Test
public void shouldShedLoad() {
List<Future<String>> l = new LinkedList<>();
LatentResource resource = new LatentResource(500L); // Make latent
ExecutorService e = Executors.newFixedThreadPool(10);
// Use up all available semaphores
for (int i = 0; i < 10; i++)
l.add(e.submit(new SemaphoreCommandInvocation(resource)));
// Wait a moment to make sure all commands are started
pause(250L); // Wrapper around Thread.sleep()
// Call will be rejected as all semaphores are in use
String s = new SemaphoreCommand(resource).execute();
assertEquals("Fallback triggered", s);
// All other calls succeed
for (Future<String> f : l)
assertEquals("Some value", get(f));
}
Fail fast
public class FailFastCommand extends HystrixCommand<String> {
private static final String COMMAND_GROUP = "default";
private final boolean preCondition;
public FailFastCommand(boolean preCondition) {
super(HystrixCommandGroupKey.Factory.asKey(COMMAND_GROUP));
this.preCondition = preCondition;
}
@Override
protected String run() throws Exception {
if (!preCondition)
throw new RuntimeException(("Fail fast"));
return "Some value";
}
}
@Test
public void shouldSucceed() {
FailFastCommand command = new FailFastCommand(true);
String s = command.execute();
assertEquals("Some value", s);
}
@Test
public void shouldFailFast() {
FailFastCommand command = new FailFastCommand(false);
try {
String s = command.execute();
fail("Did not fail fast");
} catch (Exception e) {
assertEquals(HystrixRuntimeException.class, e.getClass());
assertEquals("Fail fast", e.getCause().getMessage());
}
}
Fail silent
public class FailSilentCommand extends HystrixCommand<String> {
private static final String COMMAND_GROUP = "default";
private final boolean preCondition;
public FailSilentCommand(boolean preCondition) {
super(HystrixCommandGroupKey.Factory.asKey(COMMAND_GROUP));
this.preCondition = preCondition;
}
@Override
protected String run() throws Exception {
if (!preCondition)
throw new RuntimeException(("Fail fast"));
return "Some value";
}
@Override
protected String getFallback() {
return null; // Turn into silent failure
}
}
@Test
public void shouldSucceed() {
FailSilentCommand command = new FailSilentCommand(true);
String s = command.execute();
assertEquals("Some value", s);
}
@Test
public void shouldFailSilent() {
FailSilentCommand command = new FailSilentCommand(false);
String s = "Test value";
try {
s = command.execute();
} catch (Exception e) {
fail("Did not fail silent");
}
assertNull(s);
}
Static fallback
public class StaticFallbackCommand extends HystrixCommand<String> {
private static final String COMMAND_GROUP = "default";
private final boolean preCondition;
public StaticFallbackCommand(boolean preCondition) {
super(HystrixCommandGroupKey.Factory.asKey(COMMAND_GROUP));
this.preCondition = preCondition;
}
@Override
protected String run() throws Exception {
if (!preCondition)
throw new RuntimeException(("Fail fast"));
return "Some value";
}
@Override
protected String getFallback() {
return "Some static fallback value"; // Static fallback
}
}
@Test
public void shouldSucceed() {
StaticFallbackCommand command = new StaticFallbackCommand(true);
String s = command.execute();
assertEquals("Some value", s);
}
@Test
public void shouldProvideStaticFallback() {
StaticFallbackCommand command = new StaticFallbackCommand(false);
String s = null;
try {
s = command.execute();
} catch (Exception e) {
fail("Did not fail silent");
}
assertEquals("Some static fallback value", s);
}
Cache fallback
public class CacheClient {
private final Map<String, String> map;
public CacheClient() {
map = new ConcurrentHashMap<>();
}
public void add(String key, String value) {
map.put(key, value);
}
public String get(String key) {
return map.get(key);
}
}
public class CacheCommand extends HystrixCommand<String> {
private static final String COMMAND_GROUP = "primary";
private final CacheClient cache;
private final boolean failPrimary;
private final String req;
public CacheCommand(CacheClient cache, boolean failPrimary,
String request) {
super(HystrixCommandGroupKey.Factory.asKey(COMMAND_GROUP));
this.cache = cache;
this.failPrimary = failPrimary;
this.req = request;
}
@Override
protected String run() throws Exception {
if (failPrimary)
throw new RuntimeException("Failure of primary");
String s = req + "-o";
cache.add(req, s);
return(s);
}
…
…
@Override
protected String getFallback() {
return "Cached: " + new FBCommand(cache, req).execute();
}
private static class FBCommand extends HystrixCommand<String> {
private static final String COMMAND_GROUP = "fallback";
private final CacheClient cache;
private final String request;
public FBCommand(CacheClient cache, String request) {
super(HystrixCommandGroupKey.Factory.asKey(COMMAND_GROUP));
this.cache = cache;
this.request = request;
}
@Override
protected String run() throws Exception {
return cache.get(request);
}
}
}
@Test
public void shouldExecuteWithoutCache() {
CacheClient cache = new CacheClient();
String s = new CacheCommand(cache, false, "ping”).execute();
assertEquals("ping-o", s);
}
@Test
public void shouldRetrieveValueFromCache() {
CacheClient cache = new CacheClient();
new CacheCommand(cache, false, "ping").execute();
String s = new CacheCommand(cache, true, "ping”).execute();
assertEquals("Cached: ping-o", s);
}
@Test
public void shouldNotRetrieveAnyValue() {
CacheClient cache = new CacheClient();
String s = new CacheCommand(cache, true, "ping”).execute();
assertEquals("Cached: null", s);
}
… and so on
Advanced features
Advanced Features

•  Request Caching
•  Request Collapsing
•  Plugins

Event Notifier, Metrics Publisher, Properties Strategy,
Concurrency Strategy, Command Execution Hook
•  Contributions

Metrics Event Stream, Metrics Publisher, Java Annotations,
Clojure Bindings, …
•  Dashboard
Source: https://github.com/Netflix/Hystrix/wiki/Dashboard
Source: https://github.com/Netflix/Hystrix/wiki/Dashboard
Further reading

1.  Hystrix Wiki,

https://github.com/Netflix/Hystrix/wiki
2.  Michael T. Nygard, Release It!,
Pragmatic Bookshelf, 2007
3.  Robert S. Hanmer,

Patterns for Fault Tolerant Software,
Wiley, 2007
4.  Andrew Tanenbaum, Marten van Steen,
Distributed Systems – Principles and
Paradigms,

Prentice Hall, 2nd Edition, 2006
Wrap-up

•  Resilient software design becomes a must
•  Hystrix is a resilience library
•  Provides isolation and latency control
•  Easy to start with
•  Yet some learning curve
•  Many fault-tolerance patterns implementable
•  Many configuration options
•  Customizable
•  Operations proven

Become a resilient software developer!
It‘s all about production!
@ufried
Uwe Friedrichsen | uwe.friedrichsen@codecentric.de | http://slideshare.net/ufried | http://ufried.tumblr.com
Resilience with Hystrix
1 of 76

Recommended

Circuit breakers - Using Spring-Boot + Hystrix + Dashboard + Retry by
Circuit breakers - Using Spring-Boot + Hystrix + Dashboard + RetryCircuit breakers - Using Spring-Boot + Hystrix + Dashboard + Retry
Circuit breakers - Using Spring-Boot + Hystrix + Dashboard + RetryBruno Henrique Rother
5.6K views28 slides
Fault tolerance made easy by
Fault tolerance made easyFault tolerance made easy
Fault tolerance made easyUwe Friedrichsen
9.3K views53 slides
Introduction To Hystrix by
Introduction To HystrixIntroduction To Hystrix
Introduction To HystrixKnoldus Inc.
530 views13 slides
Hystrix 介绍 by
Hystrix 介绍Hystrix 介绍
Hystrix 介绍dennis zhuang
1.5K views24 slides
Hands on: Hystrix by
Hands on: HystrixHands on: Hystrix
Hands on: HystrixChristina Rasimus
893 views22 slides
Velocity 2016 - Operational Excellence with Hystrix by
Velocity 2016 - Operational Excellence with HystrixVelocity 2016 - Operational Excellence with Hystrix
Velocity 2016 - Operational Excellence with HystrixBilly Yuen
583 views38 slides

More Related Content

What's hot

We Are All Testers Now: The Testing Pyramid and Front-End Development by
We Are All Testers Now: The Testing Pyramid and Front-End DevelopmentWe Are All Testers Now: The Testing Pyramid and Front-End Development
We Are All Testers Now: The Testing Pyramid and Front-End DevelopmentAll Things Open
375 views60 slides
Prometheus (Monitorama 2016) by
Prometheus (Monitorama 2016)Prometheus (Monitorama 2016)
Prometheus (Monitorama 2016)Brian Brazil
4.5K views23 slides
Terraform - Taming Modern Clouds by
Terraform  - Taming Modern CloudsTerraform  - Taming Modern Clouds
Terraform - Taming Modern CloudsNic Jackson
383 views57 slides
Terraform modules restructured by
Terraform modules restructuredTerraform modules restructured
Terraform modules restructuredAmi Mahloof
435 views82 slides
The Need for Async @ ScalaWorld by
The Need for Async @ ScalaWorldThe Need for Async @ ScalaWorld
The Need for Async @ ScalaWorldKonrad Malawski
4.5K views170 slides
Atmosphere whitepaper by
Atmosphere whitepaperAtmosphere whitepaper
Atmosphere whitepaperAnarkii17
643 views33 slides

What's hot(6)

We Are All Testers Now: The Testing Pyramid and Front-End Development by All Things Open
We Are All Testers Now: The Testing Pyramid and Front-End DevelopmentWe Are All Testers Now: The Testing Pyramid and Front-End Development
We Are All Testers Now: The Testing Pyramid and Front-End Development
All Things Open375 views
Prometheus (Monitorama 2016) by Brian Brazil
Prometheus (Monitorama 2016)Prometheus (Monitorama 2016)
Prometheus (Monitorama 2016)
Brian Brazil4.5K views
Terraform - Taming Modern Clouds by Nic Jackson
Terraform  - Taming Modern CloudsTerraform  - Taming Modern Clouds
Terraform - Taming Modern Clouds
Nic Jackson383 views
Terraform modules restructured by Ami Mahloof
Terraform modules restructuredTerraform modules restructured
Terraform modules restructured
Ami Mahloof435 views
The Need for Async @ ScalaWorld by Konrad Malawski
The Need for Async @ ScalaWorldThe Need for Async @ ScalaWorld
The Need for Async @ ScalaWorld
Konrad Malawski4.5K views
Atmosphere whitepaper by Anarkii17
Atmosphere whitepaperAtmosphere whitepaper
Atmosphere whitepaper
Anarkii17643 views

Similar to Resilience with Hystrix

Resilience mit Hystrix by
Resilience mit HystrixResilience mit Hystrix
Resilience mit HystrixJava Usergroup Berlin-Brandenburg
760 views80 slides
Resilence patterns kr by
Resilence patterns krResilence patterns kr
Resilence patterns krJisung Ahn
484 views84 slides
Vert.x - Reactive & Distributed [Devoxx version] by
Vert.x - Reactive & Distributed [Devoxx version]Vert.x - Reactive & Distributed [Devoxx version]
Vert.x - Reactive & Distributed [Devoxx version]Orkhan Gasimov
510 views170 slides
Java APIs- The missing manual (concurrency) by
Java APIs- The missing manual (concurrency)Java APIs- The missing manual (concurrency)
Java APIs- The missing manual (concurrency)Hendrik Ebbers
219 views69 slides
JavaOne 2017 - TestContainers: integration testing without the hassle by
JavaOne 2017 - TestContainers: integration testing without the hassleJavaOne 2017 - TestContainers: integration testing without the hassle
JavaOne 2017 - TestContainers: integration testing without the hassleAnton Arhipov
1.3K views50 slides
Testing Java Code Effectively by
Testing Java Code EffectivelyTesting Java Code Effectively
Testing Java Code EffectivelyAndres Almiray
1.6K views46 slides

Similar to Resilience with Hystrix(20)

Resilence patterns kr by Jisung Ahn
Resilence patterns krResilence patterns kr
Resilence patterns kr
Jisung Ahn484 views
Vert.x - Reactive & Distributed [Devoxx version] by Orkhan Gasimov
Vert.x - Reactive & Distributed [Devoxx version]Vert.x - Reactive & Distributed [Devoxx version]
Vert.x - Reactive & Distributed [Devoxx version]
Orkhan Gasimov510 views
Java APIs- The missing manual (concurrency) by Hendrik Ebbers
Java APIs- The missing manual (concurrency)Java APIs- The missing manual (concurrency)
Java APIs- The missing manual (concurrency)
Hendrik Ebbers219 views
JavaOne 2017 - TestContainers: integration testing without the hassle by Anton Arhipov
JavaOne 2017 - TestContainers: integration testing without the hassleJavaOne 2017 - TestContainers: integration testing without the hassle
JavaOne 2017 - TestContainers: integration testing without the hassle
Anton Arhipov1.3K views
Testing Java Code Effectively by Andres Almiray
Testing Java Code EffectivelyTesting Java Code Effectively
Testing Java Code Effectively
Andres Almiray1.6K views
Java util concurrent by Roger Xia
Java util concurrentJava util concurrent
Java util concurrent
Roger Xia2.3K views
Fork and join framework by Minh Tran
Fork and join frameworkFork and join framework
Fork and join framework
Minh Tran1.9K views
Architecting for Microservices Part 2 by Elana Krasner
Architecting for Microservices Part 2Architecting for Microservices Part 2
Architecting for Microservices Part 2
Elana Krasner777 views
How to test infrastructure code: automated testing for Terraform, Kubernetes,... by Yevgeniy Brikman
How to test infrastructure code: automated testing for Terraform, Kubernetes,...How to test infrastructure code: automated testing for Terraform, Kubernetes,...
How to test infrastructure code: automated testing for Terraform, Kubernetes,...
Yevgeniy Brikman33.8K views
Cassandra Summit EU 2014 - Testing Cassandra Applications by Christopher Batey
Cassandra Summit EU 2014 - Testing Cassandra ApplicationsCassandra Summit EU 2014 - Testing Cassandra Applications
Cassandra Summit EU 2014 - Testing Cassandra Applications
Christopher Batey2.6K views
Breaking Dependencies To Allow Unit Testing - Steve Smith | FalafelCON 2014 by FalafelSoftware
Breaking Dependencies To Allow Unit Testing - Steve Smith | FalafelCON 2014Breaking Dependencies To Allow Unit Testing - Steve Smith | FalafelCON 2014
Breaking Dependencies To Allow Unit Testing - Steve Smith | FalafelCON 2014
FalafelSoftware671 views
Breaking Dependencies to Allow Unit Testing by Steven Smith
Breaking Dependencies to Allow Unit TestingBreaking Dependencies to Allow Unit Testing
Breaking Dependencies to Allow Unit Testing
Steven Smith1.6K views
Java design patterns by Shawn Brito
Java design patternsJava design patterns
Java design patterns
Shawn Brito832 views
Java Concurrency, Memory Model, and Trends by Carol McDonald
Java Concurrency, Memory Model, and TrendsJava Concurrency, Memory Model, and Trends
Java Concurrency, Memory Model, and Trends
Carol McDonald7.7K views
JRuby and Invokedynamic - Japan JUG 2015 by Charles Nutter
JRuby and Invokedynamic - Japan JUG 2015JRuby and Invokedynamic - Japan JUG 2015
JRuby and Invokedynamic - Japan JUG 2015
Charles Nutter1.6K views
Introduction of failsafe by Sunghyouk Bae
Introduction of failsafeIntroduction of failsafe
Introduction of failsafe
Sunghyouk Bae826 views
MicroProfile: A Quest for a Lightweight and Modern Enterprise Java Platform by Mike Croft
MicroProfile: A Quest for a Lightweight and Modern Enterprise Java PlatformMicroProfile: A Quest for a Lightweight and Modern Enterprise Java Platform
MicroProfile: A Quest for a Lightweight and Modern Enterprise Java Platform
Mike Croft2K views

More from Uwe Friedrichsen

Timeless design in a cloud-native world by
Timeless design in a cloud-native worldTimeless design in a cloud-native world
Timeless design in a cloud-native worldUwe Friedrichsen
8.7K views108 slides
Deep learning - a primer by
Deep learning - a primerDeep learning - a primer
Deep learning - a primerUwe Friedrichsen
2.8K views137 slides
Life after microservices by
Life after microservicesLife after microservices
Life after microservicesUwe Friedrichsen
20.9K views97 slides
The hitchhiker's guide for the confused developer by
The hitchhiker's guide for the confused developerThe hitchhiker's guide for the confused developer
The hitchhiker's guide for the confused developerUwe Friedrichsen
2.8K views114 slides
Digitization solutions - A new breed of software by
Digitization solutions - A new breed of softwareDigitization solutions - A new breed of software
Digitization solutions - A new breed of softwareUwe Friedrichsen
1.8K views54 slides
Real-world consistency explained by
Real-world consistency explainedReal-world consistency explained
Real-world consistency explainedUwe Friedrichsen
2.9K views60 slides

More from Uwe Friedrichsen(20)

Timeless design in a cloud-native world by Uwe Friedrichsen
Timeless design in a cloud-native worldTimeless design in a cloud-native world
Timeless design in a cloud-native world
Uwe Friedrichsen8.7K views
The hitchhiker's guide for the confused developer by Uwe Friedrichsen
The hitchhiker's guide for the confused developerThe hitchhiker's guide for the confused developer
The hitchhiker's guide for the confused developer
Uwe Friedrichsen2.8K views
Digitization solutions - A new breed of software by Uwe Friedrichsen
Digitization solutions - A new breed of softwareDigitization solutions - A new breed of software
Digitization solutions - A new breed of software
Uwe Friedrichsen1.8K views
The 7 quests of resilient software design by Uwe Friedrichsen
The 7 quests of resilient software designThe 7 quests of resilient software design
The 7 quests of resilient software design
Uwe Friedrichsen8.2K views
Excavating the knowledge of our ancestors by Uwe Friedrichsen
Excavating the knowledge of our ancestorsExcavating the knowledge of our ancestors
Excavating the knowledge of our ancestors
Uwe Friedrichsen2.7K views
The truth about "You build it, you run it!" by Uwe Friedrichsen
The truth about "You build it, you run it!"The truth about "You build it, you run it!"
The truth about "You build it, you run it!"
Uwe Friedrichsen14.1K views
The promises and perils of microservices by Uwe Friedrichsen
The promises and perils of microservicesThe promises and perils of microservices
The promises and perils of microservices
Uwe Friedrichsen4.5K views
Resilient Functional Service Design by Uwe Friedrichsen
Resilient Functional Service DesignResilient Functional Service Design
Resilient Functional Service Design
Uwe Friedrichsen6.7K views
Resilience reloaded - more resilience patterns by Uwe Friedrichsen
Resilience reloaded - more resilience patternsResilience reloaded - more resilience patterns
Resilience reloaded - more resilience patterns
Uwe Friedrichsen7K views
DevOps is not enough - Embedding DevOps in a broader context by Uwe Friedrichsen
DevOps is not enough - Embedding DevOps in a broader contextDevOps is not enough - Embedding DevOps in a broader context
DevOps is not enough - Embedding DevOps in a broader context
Uwe Friedrichsen35.6K views
Towards complex adaptive architectures by Uwe Friedrichsen
Towards complex adaptive architecturesTowards complex adaptive architectures
Towards complex adaptive architectures
Uwe Friedrichsen2.9K views
Conway's law revisited - Architectures for an effective IT by Uwe Friedrichsen
Conway's law revisited - Architectures for an effective ITConway's law revisited - Architectures for an effective IT
Conway's law revisited - Architectures for an effective IT
Uwe Friedrichsen5.7K views
Microservices - stress-free and without increased heart attack risk by Uwe Friedrichsen
Microservices - stress-free and without increased heart attack riskMicroservices - stress-free and without increased heart attack risk
Microservices - stress-free and without increased heart attack risk
Uwe Friedrichsen4.9K views

Recently uploaded

Automating a World-Class Technology Conference; Behind the Scenes of CiscoLive by
Automating a World-Class Technology Conference; Behind the Scenes of CiscoLiveAutomating a World-Class Technology Conference; Behind the Scenes of CiscoLive
Automating a World-Class Technology Conference; Behind the Scenes of CiscoLiveNetwork Automation Forum
46 views35 slides
2FA and OAuth2 in CloudStack - Andrija Panić - ShapeBlue by
2FA and OAuth2 in CloudStack - Andrija Panić - ShapeBlue2FA and OAuth2 in CloudStack - Andrija Panić - ShapeBlue
2FA and OAuth2 in CloudStack - Andrija Panić - ShapeBlueShapeBlue
50 views23 slides
Kyo - Functional Scala 2023.pdf by
Kyo - Functional Scala 2023.pdfKyo - Functional Scala 2023.pdf
Kyo - Functional Scala 2023.pdfFlavio W. Brasil
434 views92 slides
Microsoft Power Platform.pptx by
Microsoft Power Platform.pptxMicrosoft Power Platform.pptx
Microsoft Power Platform.pptxUni Systems S.M.S.A.
67 views38 slides
iSAQB Software Architecture Gathering 2023: How Process Orchestration Increas... by
iSAQB Software Architecture Gathering 2023: How Process Orchestration Increas...iSAQB Software Architecture Gathering 2023: How Process Orchestration Increas...
iSAQB Software Architecture Gathering 2023: How Process Orchestration Increas...Bernd Ruecker
50 views69 slides
Setting Up Your First CloudStack Environment with Beginners Challenges - MD R... by
Setting Up Your First CloudStack Environment with Beginners Challenges - MD R...Setting Up Your First CloudStack Environment with Beginners Challenges - MD R...
Setting Up Your First CloudStack Environment with Beginners Challenges - MD R...ShapeBlue
54 views15 slides

Recently uploaded(20)

Automating a World-Class Technology Conference; Behind the Scenes of CiscoLive by Network Automation Forum
Automating a World-Class Technology Conference; Behind the Scenes of CiscoLiveAutomating a World-Class Technology Conference; Behind the Scenes of CiscoLive
Automating a World-Class Technology Conference; Behind the Scenes of CiscoLive
2FA and OAuth2 in CloudStack - Andrija Panić - ShapeBlue by ShapeBlue
2FA and OAuth2 in CloudStack - Andrija Panić - ShapeBlue2FA and OAuth2 in CloudStack - Andrija Panić - ShapeBlue
2FA and OAuth2 in CloudStack - Andrija Panić - ShapeBlue
ShapeBlue50 views
iSAQB Software Architecture Gathering 2023: How Process Orchestration Increas... by Bernd Ruecker
iSAQB Software Architecture Gathering 2023: How Process Orchestration Increas...iSAQB Software Architecture Gathering 2023: How Process Orchestration Increas...
iSAQB Software Architecture Gathering 2023: How Process Orchestration Increas...
Bernd Ruecker50 views
Setting Up Your First CloudStack Environment with Beginners Challenges - MD R... by ShapeBlue
Setting Up Your First CloudStack Environment with Beginners Challenges - MD R...Setting Up Your First CloudStack Environment with Beginners Challenges - MD R...
Setting Up Your First CloudStack Environment with Beginners Challenges - MD R...
ShapeBlue54 views
DRBD Deep Dive - Philipp Reisner - LINBIT by ShapeBlue
DRBD Deep Dive - Philipp Reisner - LINBITDRBD Deep Dive - Philipp Reisner - LINBIT
DRBD Deep Dive - Philipp Reisner - LINBIT
ShapeBlue62 views
Backroll, News and Demo - Pierre Charton, Matthias Dhellin, Ousmane Diarra - ... by ShapeBlue
Backroll, News and Demo - Pierre Charton, Matthias Dhellin, Ousmane Diarra - ...Backroll, News and Demo - Pierre Charton, Matthias Dhellin, Ousmane Diarra - ...
Backroll, News and Demo - Pierre Charton, Matthias Dhellin, Ousmane Diarra - ...
ShapeBlue83 views
"Surviving highload with Node.js", Andrii Shumada by Fwdays
"Surviving highload with Node.js", Andrii Shumada "Surviving highload with Node.js", Andrii Shumada
"Surviving highload with Node.js", Andrii Shumada
Fwdays40 views
CloudStack Managed User Data and Demo - Harikrishna Patnala - ShapeBlue by ShapeBlue
CloudStack Managed User Data and Demo - Harikrishna Patnala - ShapeBlueCloudStack Managed User Data and Demo - Harikrishna Patnala - ShapeBlue
CloudStack Managed User Data and Demo - Harikrishna Patnala - ShapeBlue
ShapeBlue46 views
CloudStack Object Storage - An Introduction - Vladimir Petrov - ShapeBlue by ShapeBlue
CloudStack Object Storage - An Introduction - Vladimir Petrov - ShapeBlueCloudStack Object Storage - An Introduction - Vladimir Petrov - ShapeBlue
CloudStack Object Storage - An Introduction - Vladimir Petrov - ShapeBlue
ShapeBlue46 views
Declarative Kubernetes Cluster Deployment with Cloudstack and Cluster API - O... by ShapeBlue
Declarative Kubernetes Cluster Deployment with Cloudstack and Cluster API - O...Declarative Kubernetes Cluster Deployment with Cloudstack and Cluster API - O...
Declarative Kubernetes Cluster Deployment with Cloudstack and Cluster API - O...
ShapeBlue42 views
Business Analyst Series 2023 - Week 4 Session 7 by DianaGray10
Business Analyst Series 2023 -  Week 4 Session 7Business Analyst Series 2023 -  Week 4 Session 7
Business Analyst Series 2023 - Week 4 Session 7
DianaGray1080 views
KVM Security Groups Under the Hood - Wido den Hollander - Your.Online by ShapeBlue
KVM Security Groups Under the Hood - Wido den Hollander - Your.OnlineKVM Security Groups Under the Hood - Wido den Hollander - Your.Online
KVM Security Groups Under the Hood - Wido den Hollander - Your.Online
ShapeBlue102 views
Hypervisor Agnostic DRS in CloudStack - Brief overview & demo - Vishesh Jinda... by ShapeBlue
Hypervisor Agnostic DRS in CloudStack - Brief overview & demo - Vishesh Jinda...Hypervisor Agnostic DRS in CloudStack - Brief overview & demo - Vishesh Jinda...
Hypervisor Agnostic DRS in CloudStack - Brief overview & demo - Vishesh Jinda...
ShapeBlue63 views
Extending KVM Host HA for Non-NFS Storage - Alex Ivanov - StorPool by ShapeBlue
Extending KVM Host HA for Non-NFS Storage -  Alex Ivanov - StorPoolExtending KVM Host HA for Non-NFS Storage -  Alex Ivanov - StorPool
Extending KVM Host HA for Non-NFS Storage - Alex Ivanov - StorPool
ShapeBlue40 views
Future of AR - Facebook Presentation by Rob McCarty
Future of AR - Facebook PresentationFuture of AR - Facebook Presentation
Future of AR - Facebook Presentation
Rob McCarty46 views
Backup and Disaster Recovery with CloudStack and StorPool - Workshop - Venko ... by ShapeBlue
Backup and Disaster Recovery with CloudStack and StorPool - Workshop - Venko ...Backup and Disaster Recovery with CloudStack and StorPool - Workshop - Venko ...
Backup and Disaster Recovery with CloudStack and StorPool - Workshop - Venko ...
ShapeBlue77 views
GDG Cloud Southlake 28 Brad Taylor and Shawn Augenstein Old Problems in the N... by James Anderson
GDG Cloud Southlake 28 Brad Taylor and Shawn Augenstein Old Problems in the N...GDG Cloud Southlake 28 Brad Taylor and Shawn Augenstein Old Problems in the N...
GDG Cloud Southlake 28 Brad Taylor and Shawn Augenstein Old Problems in the N...
James Anderson133 views

Resilience with Hystrix

  • 1. Resilience with Hystrix An introduction Uwe Friedrichsen, codecentric AG, 2014
  • 2. @ufried Uwe Friedrichsen | uwe.friedrichsen@codecentric.de | http://slideshare.net/ufried | http://ufried.tumblr.com
  • 3. It‘s all about production!
  • 5. re•sil•ience (rɪˈzɪl yəns) also re•sil′ien•cy, n. 1.  the power or ability to return to the original form, position, etc., after being bent, compressed, or stretched; elasticity. 2.  ability to recover readily from illness, depression, adversity, or the like; buoyancy. Random House Kernerman Webster's College Dictionary, © 2010 K Dictionaries Ltd. Copyright 2005, 1997, 1991 by Random House, Inc. All rights reserved. http://www.thefreedictionary.com/resilience
  • 7. Implemented patterns •  Timeout •  Circuit breaker •  Load shedder
  • 8. Supported patterns •  Bulkheads
 (a.k.a. Failure Units) •  Fail fast •  Fail silently •  Graceful degradation of service •  Failover •  Escalation •  Retry •  ...
  • 9. That‘s been enough theory Give us some code – now!
  • 12. public class HelloCommand extends HystrixCommand<String> { private static final String COMMAND_GROUP = "default"; private final String name; public HelloCommand(String name) { super(HystrixCommandGroupKey.Factory.asKey(COMMAND_GROUP)); this.name = name; } @Override protected String run() throws Exception { return "Hello, " + name; } }
  • 13. @Test public void shouldGreetWorld() { String result = new HelloCommand("World").execute(); assertEquals("Hello, World", result); }
  • 15. @Test public void shouldExecuteSynchronously() { String s = new HelloCommand("Bob").execute(); assertEquals("Hello, Bob", s); }
  • 17. @Test public void shouldExecuteAsynchronously() { Future<String> f = new HelloCommand("Alice").queue(); String s = null; try { s = f.get(); } catch (InterruptedException | ExecutionException e) { // Handle Future.get() exceptions here } assertEquals("Hello, Alice", s); }
  • 19. @Test public void shouldExecuteReactiveSimple() { Observable<String> observable = new HelloCommand("Alice").observe(); String s = observable.toBlockingObservable().single(); assertEquals("Hello, Alice", s); }
  • 21. public class CommandHelloObserver implements Observer<String> { // Needed for communication between observer and test case private final AtomicReference<String> aRef; private final Semaphore semaphore; public CommandHelloObserver(AtomicReference<String> aRef, Semaphore semaphore) { this.aRef = aRef; this.semaphore = semaphore; } @Override public void onCompleted() { // Not needed here } @Override public void onError(Throwable e) { // Not needed here } @Override public void onNext(String s) { aRef.set(s); semaphore.release(); } }
  • 22. @Test public void shouldExecuteReactiveFull() { // Needed for communication between observer and test case AtomicReference<String> aRef = new AtomicReference<>(); Semaphore semaphore = new Semaphore(0); Observable<String> observable = new HelloCommand("Bob").observe(); Observer<String> observer = new CommandHelloObserver(aRef, semaphore); observable.subscribe(observer); // Wait until observer received a result try { semaphore.acquire(); } catch (InterruptedException e) { // Handle exceptions here } String s = aRef.get(); assertEquals("Hello, Bob", s); }
  • 24. public class FallbackCommand extends HystrixCommand<String> { private static final String COMMAND_GROUP = "default"; public FallbackCommand() { super(HystrixCommandGroupKey.Factory.asKey(COMMAND_GROUP)); } @Override protected String run() throws Exception { throw new RuntimeException("I will always fail"); } @Override protected String getFallback() { return "Powered by fallback"; } }
  • 25. @Test public void shouldGetFallbackResponse() { String s = new FallbackCommand().execute(); assertEquals("Powered by fallback", s); }
  • 27. public class ErrorPropagationCommand extends HystrixCommand<String> { private static final String COMMAND_GROUP = "default"; protected ErrorPropagationCommand() { super(HystrixCommandGroupKey.Factory.asKey(COMMAND_GROUP)); } @Override protected String run() throws Exception { throw new HystrixBadRequestException("I fail differently", new RuntimeException("I will always fail")); } @Override protected String getFallback() { return "Powered by fallback"; } }
  • 28. @Test public void shouldGetFallbackResponse() { String s = null; try { s = new ErrorPropagationCommand().execute(); fail(); // Just to make sure } catch (HystrixBadRequestException e) { assertEquals("I will fail differently", e.getMessage()); assertEquals("I will always fail", e.getCause().getMessage()); } assertNull(s); // Fallback is not triggered }
  • 34. Configuration •  Based on Archaius by Netflix
 which extends the Apache Commons Configuration Library •  Four levels of precedence 1.  Global default from code 2.  Dynamic global default property 3.  Instance default from code 4.  Dynamic instance property Provides many configuration & tuning options
  • 35. Configuration – Some examples •  hystrix.command.*.execution.isolation.strategy
 Either “THREAD” or “SEMAPHORE” (Default: THREAD) •  hystrix.command.*.execution.isolation.thread.timeoutInMilliseconds
 Time to wait for the run() method to complete (Default: 1000) •  h.c.*.execution.isolation.semaphore.maxConcurrentRequests
 Maximum number of concurrent requests when using semaphores (Default: 10) •  hystrix.command.*.circuitBreaker.errorThresholdPercentage
 Error percentage at which the breaker trips open (Default: 50) •  hystrix.command.*.circuitBreaker.sleepWindowInMilliseconds
 Time to wait before attempting to reset the breaker after tripping (Default: 5000) * must be either “default” or the command key name
  • 36. Configuration – More examples •  hystrix.threadpool.*.coreSize
 Maximum number of concurrent requests when using thread pools (Default: 10) •  hystrix.threadpool.*.maxQueueSize
 Maximum LinkedBlockingQueue size - -1 for using SynchronousQueue (Default: -1) •  hystrix.threadpool.default.queueSizeRejectionThreshold
 Queue size rejection threshold (Default: 5) … and many more * must be either “default” or the thread pool key name
  • 39. public class LatentResource { private final long latency; public LatentResource(long latency) { this.latency = ((latency < 0L) ? 0L : latency); } public String getData() { addLatency(); // This is the important part return "Some value”; } private void addLatency() { try { Thread.sleep(latency); } catch (InterruptedException e) { // We do not care about this here } } }
  • 40. public class TimeoutCommand extends HystrixCommand<String> { private static final String COMMAND_GROUP = "default"; private final LatentResource resource; public TimeoutCommand(int timeout, LatentResource resource) { super(Setter.withGroupKey( HystrixCommandGroupKey.Factory.asKey(COMMAND_GROUP)) .andCommandPropertiesDefaults( HystrixCommandProperties.Setter() .withExecutionIsolationThreadTimeoutInMilliseconds( timeout))); this.resource = resource; } @Override protected String run() throws Exception { return resource.getData(); } @Override protected String getFallback() { return "Resource timed out"; } }
  • 41. @Test public void shouldGetNormalResponse() { LatentResource resource = new LatentResource(50L); TimeoutCommand command = new TimeoutCommand(100, resource); String s = command.execute(); assertEquals("Some value", s); } @Test public void shouldGetFallbackResponse() { LatentResource resource = new LatentResource(150L); TimeoutCommand command = new TimeoutCommand(100, resource); String s = command.execute(); assertEquals("Resource timed out", s); }
  • 43. public class CircuitBreakerCommand extends HystrixCommand<String> { private static final String COMMAND_GROUP = "default"; public CircuitBreakerCommand(String name, boolean open) { super(Setter.withGroupKey( HystrixCommandGroupKey.Factory.asKey(COMMAND_GROUP)) .andCommandKey(HystrixCommandKey.Factory.asKey(name)) .andCommandPropertiesDefaults( HystrixCommandProperties.Setter() .withCircuitBreakerForceOpen(open))); } @Override protected String run() throws Exception { return("Some result"); } @Override protected String getFallback() { return "Fallback response"; } }
  • 44. @Test public void shouldExecuteWithCircuitBreakerClosed() { CircuitBreakerCommand command = new CircuitBreakerCommand("ClosedBreaker", false); String s = command.execute(); assertEquals("Some result", s); HystrixCircuitBreaker breaker = HystrixCircuitBreaker.Factory .getInstance(command.getCommandKey()); assertTrue(breaker.allowRequest()); }
  • 45. @Test public void shouldExecuteWithCircuitBreakerOpen() { CircuitBreakerCommand command = new CircuitBreakerCommand("OpenBreaker", true); String s = command.execute(); assertEquals("Fallback response", s); HystrixCircuitBreaker breaker = HystrixCircuitBreaker.Factory .getInstance(command.getCommandKey()); assertFalse(breaker.allowRequest()); }
  • 47. public class LatentCommand extends HystrixCommand<String> { private static final String COMMAND_GROUP = "default"; private final LatentResource resource; public LatentCommand(LatentResource resource) { super(HystrixCommandGroupKey.Factory.asKey(COMMAND_GROUP)); this.resource = resource; } @Override protected String run() throws Exception { return resource.getData(); } @Override protected String getFallback() { return "Fallback triggered"; } }
  • 48. @Test public void shouldShedLoad() { List<Future<String>> l = new LinkedList<>(); LatentResource resource = new LatentResource(500L); // Make latent // Use up all available threads for (int i = 0; i < 10; i++) l.add(new LatentCommand(resource).queue()); // Call will be rejected as thread pool is exhausted String s = new LatentCommand(resource).execute(); assertEquals("Fallback triggered", s); // All other calls succeed for (Future<String> f : l) assertEquals("Some value", get(f)); // wrapper for f.get() }
  • 50. public class SemaphoreCommand extends HystrixCommand<String> { private static final String COMMAND_GROUP = "default"; private final LatentResource resource; public SemaphoreCommand(LatentResource resource) { super(Setter.withGroupKey( HystrixCommandGroupKey.Factory.asKey(COMMAND_GROUP)) .andCommandPropertiesDefaults( HystrixCommandProperties.Setter() .withExecutionIsolationStrategy(HystrixCommandProperties .ExecutionIsolationStrategy.SEMAPHORE))); this.resource = resource; } @Override protected String run() throws Exception { return resource.getData(); } @Override protected String getFallback() { return "Fallback triggered"; } }
  • 51. private class SemaphoreCommandInvocation implements java.util.concurrent.Callable<String> { private final LatentResource resource; public SemaphoreCommandInvocation(LatentResource resource) { this.resource = resource; } @Override public String call() throws Exception { return new SemaphoreCommand(resource).execute(); } }
  • 52. @Test public void shouldShedLoad() { List<Future<String>> l = new LinkedList<>(); LatentResource resource = new LatentResource(500L); // Make latent ExecutorService e = Executors.newFixedThreadPool(10); // Use up all available semaphores for (int i = 0; i < 10; i++) l.add(e.submit(new SemaphoreCommandInvocation(resource))); // Wait a moment to make sure all commands are started pause(250L); // Wrapper around Thread.sleep() // Call will be rejected as all semaphores are in use String s = new SemaphoreCommand(resource).execute(); assertEquals("Fallback triggered", s); // All other calls succeed for (Future<String> f : l) assertEquals("Some value", get(f)); }
  • 54. public class FailFastCommand extends HystrixCommand<String> { private static final String COMMAND_GROUP = "default"; private final boolean preCondition; public FailFastCommand(boolean preCondition) { super(HystrixCommandGroupKey.Factory.asKey(COMMAND_GROUP)); this.preCondition = preCondition; } @Override protected String run() throws Exception { if (!preCondition) throw new RuntimeException(("Fail fast")); return "Some value"; } }
  • 55. @Test public void shouldSucceed() { FailFastCommand command = new FailFastCommand(true); String s = command.execute(); assertEquals("Some value", s); } @Test public void shouldFailFast() { FailFastCommand command = new FailFastCommand(false); try { String s = command.execute(); fail("Did not fail fast"); } catch (Exception e) { assertEquals(HystrixRuntimeException.class, e.getClass()); assertEquals("Fail fast", e.getCause().getMessage()); } }
  • 57. public class FailSilentCommand extends HystrixCommand<String> { private static final String COMMAND_GROUP = "default"; private final boolean preCondition; public FailSilentCommand(boolean preCondition) { super(HystrixCommandGroupKey.Factory.asKey(COMMAND_GROUP)); this.preCondition = preCondition; } @Override protected String run() throws Exception { if (!preCondition) throw new RuntimeException(("Fail fast")); return "Some value"; } @Override protected String getFallback() { return null; // Turn into silent failure } }
  • 58. @Test public void shouldSucceed() { FailSilentCommand command = new FailSilentCommand(true); String s = command.execute(); assertEquals("Some value", s); } @Test public void shouldFailSilent() { FailSilentCommand command = new FailSilentCommand(false); String s = "Test value"; try { s = command.execute(); } catch (Exception e) { fail("Did not fail silent"); } assertNull(s); }
  • 60. public class StaticFallbackCommand extends HystrixCommand<String> { private static final String COMMAND_GROUP = "default"; private final boolean preCondition; public StaticFallbackCommand(boolean preCondition) { super(HystrixCommandGroupKey.Factory.asKey(COMMAND_GROUP)); this.preCondition = preCondition; } @Override protected String run() throws Exception { if (!preCondition) throw new RuntimeException(("Fail fast")); return "Some value"; } @Override protected String getFallback() { return "Some static fallback value"; // Static fallback } }
  • 61. @Test public void shouldSucceed() { StaticFallbackCommand command = new StaticFallbackCommand(true); String s = command.execute(); assertEquals("Some value", s); } @Test public void shouldProvideStaticFallback() { StaticFallbackCommand command = new StaticFallbackCommand(false); String s = null; try { s = command.execute(); } catch (Exception e) { fail("Did not fail silent"); } assertEquals("Some static fallback value", s); }
  • 63. public class CacheClient { private final Map<String, String> map; public CacheClient() { map = new ConcurrentHashMap<>(); } public void add(String key, String value) { map.put(key, value); } public String get(String key) { return map.get(key); } }
  • 64. public class CacheCommand extends HystrixCommand<String> { private static final String COMMAND_GROUP = "primary"; private final CacheClient cache; private final boolean failPrimary; private final String req; public CacheCommand(CacheClient cache, boolean failPrimary, String request) { super(HystrixCommandGroupKey.Factory.asKey(COMMAND_GROUP)); this.cache = cache; this.failPrimary = failPrimary; this.req = request; } @Override protected String run() throws Exception { if (failPrimary) throw new RuntimeException("Failure of primary"); String s = req + "-o"; cache.add(req, s); return(s); } …
  • 65. … @Override protected String getFallback() { return "Cached: " + new FBCommand(cache, req).execute(); } private static class FBCommand extends HystrixCommand<String> { private static final String COMMAND_GROUP = "fallback"; private final CacheClient cache; private final String request; public FBCommand(CacheClient cache, String request) { super(HystrixCommandGroupKey.Factory.asKey(COMMAND_GROUP)); this.cache = cache; this.request = request; } @Override protected String run() throws Exception { return cache.get(request); } } }
  • 66. @Test public void shouldExecuteWithoutCache() { CacheClient cache = new CacheClient(); String s = new CacheCommand(cache, false, "ping”).execute(); assertEquals("ping-o", s); } @Test public void shouldRetrieveValueFromCache() { CacheClient cache = new CacheClient(); new CacheCommand(cache, false, "ping").execute(); String s = new CacheCommand(cache, true, "ping”).execute(); assertEquals("Cached: ping-o", s); } @Test public void shouldNotRetrieveAnyValue() { CacheClient cache = new CacheClient(); String s = new CacheCommand(cache, true, "ping”).execute(); assertEquals("Cached: null", s); }
  • 69. Advanced Features •  Request Caching •  Request Collapsing •  Plugins
 Event Notifier, Metrics Publisher, Properties Strategy, Concurrency Strategy, Command Execution Hook •  Contributions
 Metrics Event Stream, Metrics Publisher, Java Annotations, Clojure Bindings, … •  Dashboard
  • 72. Further reading 1.  Hystrix Wiki,
 https://github.com/Netflix/Hystrix/wiki 2.  Michael T. Nygard, Release It!, Pragmatic Bookshelf, 2007 3.  Robert S. Hanmer,
 Patterns for Fault Tolerant Software, Wiley, 2007 4.  Andrew Tanenbaum, Marten van Steen, Distributed Systems – Principles and Paradigms,
 Prentice Hall, 2nd Edition, 2006
  • 73. Wrap-up •  Resilient software design becomes a must •  Hystrix is a resilience library •  Provides isolation and latency control •  Easy to start with •  Yet some learning curve •  Many fault-tolerance patterns implementable •  Many configuration options •  Customizable •  Operations proven Become a resilient software developer!
  • 74. It‘s all about production!
  • 75. @ufried Uwe Friedrichsen | uwe.friedrichsen@codecentric.de | http://slideshare.net/ufried | http://ufried.tumblr.com