Netflix Hystrix Asynchronous Execution Example
In this tutorial we show you how to execute a asynchronous Hystrix
command. We use the HystrixCommand
which is used to wrap code that will execute potentially risky functionality. Typically meaning a service call over the network with fault and latency tolerance.
Project Structure
Let’s start by looking at the project structure.
Maven Dependencies
We use Apache Maven to manage our project dependencies. Make sure the following dependencies reside on the class-path.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.memorynotfound.netflix.hystrix</groupId>
<artifactId>asynchronous-execution</artifactId>
<version>1.0.0-SNAPSHOT</version>
<url>https://memorynotfound.com</url>
<name>Netflix Hystrix - ${project.artifactId}</name>
<dependencies>
<dependency>
<groupId>com.netflix.hystrix</groupId>
<artifactId>hystrix-core</artifactId>
<version>1.5.3</version>
</dependency>
<!-- logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.25</version>
</dependency>
<!-- testing -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
Netflix Hystrix Asynchronous Execution Example
This example uses the HystrixCommand
which is used to wrap code that will execute potentially risky functionality (typically meaning a service call over the network) with fault and latency tolerance, statistics and performance metics capture, circuit breaker and bulkhead functionality.
package com.memorynotfound.netflix.hystrix;
import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;
public class GreetingCommand extends HystrixCommand<String> {
private final String name;
public GreetingCommand(String name) {
super(HystrixCommandGroupKey.Factory.asKey("GreetingGroup"));
this.name = name;
}
@Override
protected String run() throws Exception {
if (this.name == null){
throw new IllegalArgumentException("name sould not be 'null'.");
}
return "Hello " + this.name + "!";
}
@Override
protected String getFallback() {
return "Hello Guest!";
}
}
Writing a Asynchronous Fallback
If queue()
fails in any way then the getFallback()
method will be invoked to provide an opportunity to return a fallback response. This should typically not require network transport. In other words, this should be a static, stubbed or cached result that can immediately be returned upon failure. If network traffic is wanted for fallback (such as going to MemCache or Redis) then the fallback implementation should invoke another HystrixCommand
instance that protects against that network access and possibly has another level of fallback that does not involve network access.
Unit Test Netflix Hystrix Asynchronous Execution with JUnit
You can execute a HystrixCommand
asynchronously by using the queue()
method. This will queue up the command on the thread pool and return a Futrue
to get the result once it completes. In the first JUnit test, we validate a successful run. The second JUnit test validates if the getFallback()
method is executed.
Note: if theHystrixCommand
is configured to not run in a separate thread, this will have the same effect asexecute()
and will block.
package com.memorynotfound.netflix.hystrix.test;
import com.memorynotfound.netflix.hystrix.GreetingCommand;
import org.junit.Test;
import java.util.concurrent.Future;
import static org.junit.Assert.*;
public class GreetingCommandTest {
@Test
public void testAsynchronousGreeting1() throws Exception {
GreetingCommand command1 = new GreetingCommand("World");
GreetingCommand command2 = new GreetingCommand("John");
Future fWorld = new GreetingCommand("World").queue();
Future fJohn = new GreetingCommand("John").queue();
assertEquals("Hello World!", fWorld.get());
assertEquals("Hello John!", fJohn.get());
assertFalse(command1.isResponseFromFallback());
assertFalse(command2.isResponseFromFallback());
}
@Test
public void testAsynchronousGreetingFallBack() throws Exception {
try {
GreetingCommand command = new GreetingCommand(null);
Future fNull = command.queue();
assertEquals("Hello Guest!", fNull.get());
assertTrue(command.isResponseFromFallback());
} catch (Exception e){
fail("we should not get an exception as we return a fallback");
}
}
}
JUnit Test Results
When we run all of our JUnit tests, we receive the following output.
References
- Netflix Hystrix Documentation
- Netflix Hystrix JavaDoc API
- HystrixCommand JavaDoc
- HystrixCommand queue() JavaDoc