How to handle Fault Tolerance in your Enterprise applications and Microservices
Microprofile fault tolerance specification is a way for your application to handle the unavailability of a service by using a set of different policies. In this tutorial we will see how we can apply these policies in an application that can be run in Thorntail runtime.

Thorntail is a Microprofile compliant environment, therefore you can combine the power of Enterprise API with the enhancement provided by Microprofile. Let’s see which policies can be used to improve the resiliency of your applications by using the FaultTolerance specification available in Microprofile:
Timeout
By using the @Timeout annotation, you can specify the maximum time (in ms) allowed to return a response in a method. Here is an example:
@GET
@Path("/json")
@Produces(MediaType.APPLICATION_JSON)
@Timeout(250)
public SimpleProperty getPropertyJSON ()
{
SimpleProperty p = new SimpleProperty("key","value");
randomSleep();
return p;
}
private void randomSleep() {
try {
Thread.sleep(new Random().nextInt(500));
}
catch (Exception exc) {
exc.printStackTrace();
}
}
You can further specify a @Fallback policy which states which fallback method should be specified in case of failure:
@GET
@Path("/json")
@Produces(MediaType.APPLICATION_JSON)
@Timeout(250)
@Fallback(fallbackMethod = "fallbackJSON")
public SimpleProperty getPropertyJSON ()
{
SimpleProperty p = new SimpleProperty("key","value");
randomSleep();
return p;
}
public SimpleProperty fallbackJSON()
{
SimpleProperty p = new SimpleProperty("key","fallback");
return p;
}
Retry
The retry annotation is essential to deal with unstable services. MicroProfile uses @Retry to specify the retry when a certain Exception is raised. You can allow retrying for a certain number of times before cancelling the retry. In this example we allow up to 4 retries when the RuntimeException is thrown:
@GET
@Path("/text")
@Retry(maxRetries = 4, retryOn = RuntimeException.class)
public String getHello ()
{
if (new Random().nextFloat() < 0.5f) {
System.out.println("Error!!!");
throw new RuntimeException("Resource failure.");
}
return "hello world!";
}
Circuit Breaker
Circuit Breaker is a key pattern for creating resilient Microservices. It can be used to prevent repeatable timeout Exceptions by instantly rejecting the requests. MicroProfile Fault Tolerance uses @CircuitBreaker to control the client calls.
The software circuit breaker works much like an electrical circuit breaker therefore it can be in three states:

- Closed state: A closed circuit represents a fully functional system, which is available to its clients
- Half open circuit: When some failures are detected the state can change to half-open. In this state, it checks whether the failed component is restored. If so, it closes the circuit. otherwise, it moves to the Open state
- Open state. An open state means the service is temporarly disabled. You can specify how much time after checks are done to verify if it’s safe to switch to half-open state.
Here is an example:
@GET
@Path("/xml")
@Produces(MediaType.APPLICATION_XML)
@CircuitBreaker(successThreshold = 5, requestVolumeThreshold = 4, failureRatio=0.75, delay = 1000)
public SimpleProperty getPropertyXML ()
{
SimpleProperty p = buildPOJO();
return p;
}
private SimpleProperty buildPOJO() {
if (new Random().nextFloat() < 0.5f) {
System.out.println("Error!!!");
throw new RuntimeException("Resource failure.");
}
SimpleProperty p = new SimpleProperty("key","value");
return p;
}
The above code-snippet means the method getPropertyXML applies the CircuitBreaker policy. For the last 4 invocations, if 75% failed then open the circuit. The circuit will stay open for 1000ms and then back to half open. When a circuit is open, A CircuitBreakerOpenException will be thrown instead of actually invoking the method.
org.jboss.resteasy.spi.UnhandledException: org.eclipse.microprofile.faulttolerance.exceptions.CircuitBreakerOpenException: getPropertyXML
at org.jboss.resteasy.core.ExceptionHandler.handleApplicationException(ExceptionHandler.java:78)
at org.jboss.resteasy.core.ExceptionHandler.handleException(ExceptionHandler.java:222)
Here is a full code example:
package com.itbuzzpress.microprofile.service;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.container.AsyncResponse;
import javax.ws.rs.container.Suspended;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import java.util.Random;
import com.itbuzzpress.microprofile.model.SimpleProperty;
import org.eclipse.microprofile.faulttolerance.Retry;
import org.eclipse.microprofile.faulttolerance.Timeout;
import org.eclipse.microprofile.faulttolerance.Fallback;
import org.eclipse.microprofile.faulttolerance.CircuitBreaker;
@Path("/simple")
public class SimpleRESTService {
@GET
@Path("/text")
@Retry(maxRetries = 4, retryOn = RuntimeException.class)
public String getHello ()
{
if (new Random().nextFloat() < 0.5f) {
System.out.println("Error!!!");
throw new RuntimeException("Resource failure.");
}
return "hello world!";
}
@GET
@Path("/json")
@Produces(MediaType.APPLICATION_JSON)
@Timeout(250)
@Fallback(fallbackMethod = "fallbackJSON")
public SimpleProperty getPropertyJSON ()
{
SimpleProperty p = new SimpleProperty("key","value");
randomSleep();
return p;
}
public SimpleProperty fallbackJSON()
{
SimpleProperty p = new SimpleProperty("key","fallback");
return p;
}
@GET
@Path("/xml")
@Produces(MediaType.APPLICATION_XML)
@CircuitBreaker(successThreshold = 5, requestVolumeThreshold = 4, failureRatio=0.75, delay = 1000)
public SimpleProperty getPropertyXML ()
{
SimpleProperty p = buildPOJO();
return p;
}
private void randomSleep() {
try {
Thread.sleep(new Random().nextInt(500));
}
catch (Exception exc) {
exc.printStackTrace();
}
}
private SimpleProperty buildPOJO() {
if (new Random().nextFloat() < 0.5f) {
System.out.println("Error!!!");
throw new RuntimeException("Resource failure.");
}
SimpleProperty p = new SimpleProperty("key","value");
return p;
}
}
In order to compile and run the above example, the microprofile-fault-tolerance fraction needs to be included in your pom.xml, plus the other fractions needed such as jaxrs and cdi,:
<dependency>
<groupId>io.thorntail</groupId>
<artifactId>jaxrs</artifactId>
</dependency>
<dependency>
<groupId>io.thorntail</groupId>
<artifactId>cdi</artifactId>
</dependency>
<dependency>
<groupId>io.thorntail</groupId>
<artifactId>microprofile-fault-tolerance</artifactId>
</dependency>
Recommended Articles
Implement MicroProfile Fault Tolerance API in Java to Ensure Reliability
Learn how to use the Microprofile Fault Tolerance specification to implement retry, timeout, fallback, and circuit breaker policies for resilient microservices development.
Configure MicroProfile API for Enterprise Java Applications using Thorntail or Quarkus
Learn how to use Microprofile API in Java EE applications with Thorntail and Quarkus, including dependency management and health checks.
Build and Deploy Microprofile Applications on Wildfly with MicroProfile API Support
Learn how to create and deploy Microprofile applications on Wildfly with the latest version of Microprofile API support, combining Jakarta EE and MicroProfile APIs.
Configuring Microservices with WildFly and MicroProfile Configuration
Learn how to externalize and inject configuration properties for your microservices using WildFly and the MicroProfile Configuration API.