Skip to main content

This is the final of a series of 3 articles dedicated to the MicroProfile Fault Tolerance. We started by introducing and giving an overview of the specification in “MicroProfile Fault Tolerance, Take 2”. Next, we explained the different annotations and their options in “MicroProfile Fault Tolerance Annotations”.

Now we take a look at practical MicroProfile Fault Tolerance examples using TomEE 7.1.  This version of TomEE is compliant with MicroProfile v1.2 and includes the Geronimo Safegard library implementing the Fault Tolerance v1.0 spec.

The MicroProfile Samples project

We’ll be using the microprofile-samples project created by Roberto Cortez and which is available on Github as microprofile-samples. The purpose of the microprofile-samples project is to provide simple working examples that you can execute to learn more about the spec and to get inspiration for your own projects. It’s open source and Apache 2 licensed.

To run the examples, we assume that you already have installed on your computer the following software:

  • Git command line tool
  • Java JDK 8+
  • Maven build tool
  • The Curl command line tool is optional but handy.

Let’s start by cloning the microprofile-samples project using this git command:

git clone https://github.com/tomitribe/microprofile-samples.git

Now that you have cloned the repository, you can import it to your IDE or build it with Maven using the following commands:

cd microprofile-samples
mvn clean install 

Inside the microprofile-samples project, we include the arquillian, the MicroProfile Config and the Fault Tolerance sub-projects.

The arquillian sub-project was created to simplify the test classes by not requiring a deployment folder. It will simply use the built artifacts from each sample sub-project.

Let’s go to the Fault tolerance sample:

cd fault-tolerance
ls -al

There are a few sub-projects, in alphabetical order:

  • bulkhead
  • circuit-breaker
  • fallback
  • retry
  • timeout
  • timeout-retry-fallback

Each sub-project exists to demonstrate a particular part of the spec.

All sub-projects have a similar structure. Using the timeout as a reference, we see the main source code containing the ApplicationBean class is launched on startup and the MovieResource class is used to publish the REST endpoints.

The MovieResourceTest class is the Arquillian integration test that you can use.

All MovieResource< CDI beans have at least a findAll() method to return a list of movies. We will use it as a Guinea Pig to demonstrate the behavior of the Fault Tolerance annotations. This is the resource for the Timeout example:

@ApplicationScoped
@Path("/movies")
public class MovieResource {

   /**
    * After a default timeout of 1 second, the request will fail with TimeoutException.
    *
    * @return the movies list
    */
   @GET
   @Timeout
   public List findAll() {
       ...
   }
}

Different samples will have different annotations and control logic to trigger faults inside the findAll() method, but they are all built following this project structure.

Trying out the samples

The sample applications can be executed in 3 different ways:

  • Using the Arquillian tests inside each sub-project. You can use your IDE to run each of the examples. Look for the MovieResourceTest classes.
  • The applications are packaged using the WAR file format. Most of them can be deployed by going to a subproject and execute the TomEE Maven plugin as shown below:
cd timeout
mvn clean package -DskipTests tomee:run
  • Running a single fat jar that bundles the app and TomEE. If the fat jar is not in the timeout/target folder you need to build the project first using the following commands:
cd timeout
mvn clean package -DskipTestse>

java -jar target/retry-1.0-SNAPSHOT-exec.jar

The Fallback sample

Let’s see in detail a more interesting example, the Fallback. This pattern allows us to declare an alternative implementation to use when something goes wrong. The following is the findAll() method in the MovieResource class:

@GET
@CircuitBreaker(failOn = BusinessException.class)
@Fallback(MovieFindAllFallbackHandler.class)
public List findAll() {
   throw new BusinessException();
}

As you can see, the method is set up to always fail. When the method fails the circuit-breaker will open the circuit (refusing requests) right away in response to the BusinessException being thrown. Because we are declaring an alternative execution path, the fallback, the client still gets a response.

In the same package, the MovieFindAllFallbackHandler provides the alternative execution:

public class MovieFindAllFallbackHandler implements FallbackHandler<List> {
   @Override
   public List handle(final ExecutionContext context) {
       return Stream.of("The Terminator", "The Matrix", "Rambo").collect(toList());
   }
}

Let’s run this on TomEE. Go to the project folder .../microprofile-samples/fault-tolerance/fallback/ and build the project:

mvn clean package -DskipTests

Then run the embedded TomEE server with the application:

java -jar target/fallback-1.0-SNAPSHOT-exec.jar

On the log you can spot where the REST endpoints are being published:

TomEE will be running after the Server startup message:

...INFO [main] sun.reflect.DelegatingMethodAccessorImpl.invoke Server startup in 2271 ms

Once TomEE is running you can make some requests. We could use a browser but it would not display the list of movies because we are returning pure a JSON payload. Instead, we will use a command line curl command to get the list of movies:

~$ curl -i http://localhost:8080/fallback-1.0-SNAPSHOT/movies/
HTTP/1.1 200
Date: Tue, 02 Oct 2018 08:06:40 GMT
Content-Type: application/json
Transfer-Encoding: chunked
Server: Apache TomEE

["The Terminator","The Matrix","Rambo"]

As you can see, the error is isolated by the circuit breaker and the fallback is giving us the response.

The timeout-retry-fallback sample

You might be thinking “this fancy fallback is nothing more than a glorified catch from a try block”. In a sense it is, but it’s much more powerful…

Take the timeout-retry-fallback sub-project:

@GET
@Timeout // default 1 sec.
@Retry(delay = 1000, maxRetries = 2) 
@Fallback(MovieFindAllFallbackHandler.class)
public List findAll() {
// operation taking forever to complete.
}

In here, we can very easily wait for an operation to complete if there is a timeout. When timeouts happen, we can retry twice, with a small delay between calls. If, in the end, the request is not successful, the fallback will be invoked.

Try out the other patterns, with them you can precisely control the execution flow and also keep things tidy. You will need less code to perform these operations and that also means fewer bugs.

In future versions of TomEE, because Fault Tolerance v.1.1 defines integrations with the Configuration and Monitoring APIs, you will also be able to override the annotation options without the need of a re-deploy and receive metrics out of the box.

Thanks for reading! Feel free to send us a pull request with MicroProfile samples to include in the project.  Stay tuned for more MicroProfile posts!

Bruno Baptista

Bruno Baptista

Bruno is a well versed Java and Open Source technology developer and a Senior Software Engineer at Tomitribe. With over 10 years as an enterprise level engineer, he has lead QA and development teams, garnered skills in design and development process.
brunobat_

Leave a Reply