Getting started with MicroProfile FaultTolerance API

The Microprofile Fault Tolerance specification has been specifically built to make your microservices to common failures like network problems or an IOException.

In this tutorial we will learn how to use some patterns like @Timeout, @Retry, @Fallback and @CircuitBreaker policies to drive an alternative result when an execution does not complete successfully.

Let’s start from the @Timeout annotation which prevents from the execution from waiting forever.

Example:

@GET
@Path("/hello")
@Timeout(250)
public String getData()
{
	randomSleep();

	return "Random string " + UUID.randomUUID().toString();
}

You can also add a @Retry and @Fallback policy to refine your fault-tolerance policy.

  • @Retry lets you retry the execution of the method in case of failure, up to a maximum number of retries
  • @Fallback lets you drive the execution to a fallback method, to avoid returning a TimeoutException.
package com.mastertheboss.microprofile.service;

import org.eclipse.microprofile.faulttolerance.Fallback;
import org.eclipse.microprofile.faulttolerance.Timeout;

import javax.annotation.PostConstruct;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import java.util.Random;
import java.util.UUID;

@Path("/")
public class SimpleRESTService {

	String cachedData;

	@PostConstruct
	public void init() {
		cachedData = UUID.randomUUID().toString();
	}
	@GET
	@Path("/hello")
	@Timeout(250)
	@Retry(maxRetries = 2)
	@Fallback(fallbackMethod = "getCachedData")
	public String getData()
	{
		randomSleep();

		return "Random string " + UUID.randomUUID().toString();
	}
	private void randomSleep() {
		try {
			Thread.sleep(new Random().nextInt(400));
		} catch (Exception e) {
            System.out.println("The application is taking too long...");

		}
	}

	public String getCachedData()
	{

		return "Random (cached) String is "+cachedData;
	}
}

Sometimes you might want an application to wait before it issues a retry request. For example, if the failure is caused by a sudden spike in requests or a loss of connectivity, waiting might decrease the chance that a previous failure occurs. In these cases, you can define a delay in the Retry policy using these parameters:

  • delay: The amount of time to wait before retrying a request. The value must be an integer greater than or equal to 0 and be less than the value for maxDuration. The default is 0.
  • delayUnit: The unit of time for the delay parameter as described by the java.time.temporal.ChronoUnit class. The default is ChronoUnit.MILLIS.
  • durationUnit: defines a standard set of date period units, including NANOS, MICROS, MILLIS, SECONDS, MINUTES, and HOURS.
@Retry(retryOn = TimeoutException.class,
       maxRetries = 4,
       maxDuration = 10,
       durationUnit = ChronoUnit.SECONDS,
       delay = 200, delayUnit = ChronoUnit.MILLIS)           

Finally, you can specify an Exception class that triggers a retry. You can identify more than one exception as an array of values. For example,

@Retry(retryOn = {RuntimeException.class, TimeoutException.class}).

The default is java.lang.Exception.class.

Using a Circuit Breaker Policy

A Circuit Breaker policy can be used to prevent repeated failures when a service is rated as not functional. There are three circuit states:

  • Closed: In normal conditions, the circuit is closed. In case of failure occurs, the Circuit Breaker tracks the event and the requestVolumeThreshold and failureRatio parameters determine the conditions under which the breaker will transition the circuit to open.
  • Open: When the circuit is open, any call to the service will fail immediately. A delay may be configured for the Circuit Breaker. After the delay, the circuit transitions to half-open state.
  • Half-open: In half-open state, by default one trial call to the service is allowed. Should it fail, the circuit will return to open state. You can configure the number of trials with the successThreshold parameter. After the specified number of successful executions, the circuit will be closed.

A method or a class can be annotated with @CircuitBreaker, as in this example:

@CircuitBreaker(successThreshold = 10, requestVolumeThreshold = 4, failureRatio=0.75, delay = 1000)
public Service checkBalance() {
    counterForInvokingService++;
    return checkBalanceService();
}

The above code excerpt applies the CircuitBreaker policy, which is to open the circuit once 3 (4×0.75) failures occur among the rolling window of 4 consecutive invocation. The circuit will stay open for 1000ms and then back to half open. After 10 consecutive successful invocations, the circuit will be back to close again.

Setting up projects with FaultTolerance API

There are several platforms which are compatible with FaultTolearance API. In particular you can run the above examples in any of the following platforms:

Thorntail:

Include the following dependencies:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>io.thorntail</groupId>
            <artifactId>bom-all</artifactId>
            <version>${version.thorntail}</version>
            <scope>import</scope>
            <type>pom</type>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependency>
    <groupId>io.thorntail</groupId>
    <artifactId>microprofile-fault-tolerance</artifactId>
</dependency>

Quarkus:

Include the following dependencies:

<dependencyManagement>
  <dependencies>
	  <dependency>
	    <groupId>io.quarkus</groupId>
	    <artifactId>quarkus-bom</artifactId>
	    <version>${quarkus.version}</version>
	    <type>pom</type>
	    <scope>import</scope>
	  </dependency>
  </dependencies>
</dependencyManagement>

<dependency>
  <groupId>io.quarkus</groupId>
  <artifactId>quarkus-smallrye-fault-tolerance</artifactId>
</dependency> 

Tom EE:

<dependency>
	<groupId>org.eclipse.microprofile</groupId>
	<artifactId>microprofile</artifactId>
	<version>${version.microprofile}</version>
	<type>pom</type>
	<scope>provided</scope>
</dependency>

Source code for this tutorial: https://github.com/fmarchioni/mastertheboss/tree/master/micro-services/mp-fault-tolerance

Found the article helpful? if so please follow us on Socials