Netflix Hystrix Synchronous Execution Example
In this tutorial we show you how to execute a synchronous 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>synchronous-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 Synchronous 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. This command is essentially a blocking command but provides an Obsevable
facade if used with observe()
.
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 Synchronous Fallback
If execute()
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 Synchronous Execution with JUnit
You can execute a HystrixCommand
synchronously with the execute()
method. This is a blocking execution and returns the result of run()
method execution or fallback from getFallback()
if the command fails for any reason. In the first JUnit test, we validate a successful run. The second JUnit test validates if the getFallback()
method is executed.
package com.memorynotfound.netflix.hystrix.test;
import com.memorynotfound.netflix.hystrix.GreetingCommand;
import org.junit.Test;
import static org.junit.Assert.*;
public class GreetingCommandTest {
@Test
public void testGreeting() throws Exception {
assertEquals("Hello World!", new GreetingCommand("World").execute());
GreetingCommand command = new GreetingCommand("John");
assertEquals("Hello John!", command.execute());
assertFalse(command.isResponseFromFallback());
}
@Test
public void testGreetingFallBack() throws Exception {
try {
GreetingCommand command = new GreetingCommand(null);
assertEquals("Hello Guest!", command.execute());
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.