Building fault-tolerant microservices with the @Fallback annotation

duration 20 minutes
Git clone to get going right away:
git clone https://github.com/OpenLiberty/guide-microprofile-fallback.git
Copy Github clone command

You’ll explore how to manage the impact of failures using MicroProfile Fault Tolerance by adding fallback behavior to microservice dependencies.

What you’ll learn

You will learn how to use MicroProfile (MP) Fault Tolerance to build resilient microservices that reduce the impact from failure and ensure continued operation of services.

MP Fault Tolerance provides a simple and flexible solution to build fault-tolerant microservices. Fault tolerance leverages different strategies to guide the execution and result of logic. As stated in the MicroProfile website, retry policies, bulkheads, and circuit breakers are popular concepts in this area. They dictate whether and when executions take place, and fallbacks offer an alternative result when an execution does not complete successfully.

The application that you will be working with is an inventory service, which collects, stores, and returns the system properties. It uses the system service to retrieve the system properties for a particular host. You will add fault tolerance to the inventory service so that it reacts accordingly when the system service is unavailable.

You will use the @Fallback annotations from the MicroProfile Fault Tolerance specification to define criteria for when to provide an alternative solution for a failed execution.

Getting started

The fastest way to work through this guide is to clone the Git repository and use the projects that are provided inside:

git clone https://github.com/openliberty/guide-microprofile-fallback.git
cd guide-microprofile-fallback

The start directory contains the starting project that you will build upon.

The finish directory contains the finished project that you will build.

Try what you’ll build

The finish directory in the root of this guide contains the finished implementation for the application. You can give it a try before you proceed with building your own.

To try out the application, navigate to the finish directory and run the following command:

mvn install liberty:start-server

Point your browser to the http://localhost:9080/inventory/systems/localhost URL, which accesses the inventory service with a localhost host name. You see the system properties for this host. When you visit this URL, some of these system properties, such as the OS name and user name, are automatically stored in the inventory.

Update the CustomConfigSource configuration file.
resources/CustomConfigSource.json

CustomConfigSource.json

1{"config_ordinal":500,
2"io_openliberty_guides_system_inMaintenance":false}

Change the io_openliberty_guides_system_inMaintenance property from false to true and save the file.

You do not need to restart the server. Next, return to your browser and point back to the http://localhost:9080/inventory/systems/localhost URL. The fallback mechanism is triggered because the system service is now in maintenance. You see the cached properties for this localhost.

When you are done checking out the application, go to the CustomConfigSource.json file again.

Update the CustomConfigSource configuration file.
resources/CustomConfigSource.json

Change the io_openliberty_guides_system_inMaintenance property from true to false to set this condition back to its original value.

Stop the Open Liberty server:

mvn liberty:stop-server

Enabling fault tolerance

Navigate to the start directory to begin.

The MicroProfile Fault Tolerance API was added as a dependency to your pom.xml file. Look for the dependency with the mpFaultTolerance artifact ID. Adding this dependency allows you to use the fault tolerance policies in your microservices.

You can also find the mpFaultTolerance feature in your src/main/liberty/config/server.xml server configuration, which turns on MicroProfile Fault Tolerance capabilities in Open Liberty.

To easily work through this guide, the two provided microservices are set up to run on the same server. To simulate the availability of the services and then to enable fault tolerance, dynamic configuration with MicroProfile Configuration is used so that you can easily take one service or the other down for maintenance. If you want to learn more about setting up dynamic configuration, see Configuring microservices.

The following two steps set up the dynamic configuration on the system service and its client. You can move on to the next section, which adds the fallback mechanism on the inventory service.

First, the src/main/java/io/openliberty/guides/system/SystemResource.java file has the isInMaintenance() condition, which determines that the system properties are returned only if you set the io_openliberty_guides_system_inMaintenance configuration property to false in the CustomConfigSource file. Otherwise, the service returns a Status.SERVICE_UNAVAILABLE message, which makes it unavailable.

Next, the src/main/java/io/openliberty/guides/inventory/client/SystemClient.java file makes a request to the system service through the MicroProfile Rest Client API. If you want to learn more about MicroProfile Rest Client, you can follow the Consuming RESTful services with template interfaces guide. The system service as described in the SystemResource.java file may return a Status.SERVICE_UNAVAILABLE message, which is a 503 status code. This code indicates that the server being called is unable to handle the request because of a temporary overload or scheduled maintenance, which would likely be alleviated after some delay. To simulate that the system is unavailable, an IOException is thrown.

The InventoryManager class calls the getProperties() method in the SystemClient.java class. You will look into the InventoryManager class in more detail in the next section.

SystemResource.java

 1package io.openliberty.guides.system;
 2
 3import javax.enterprise.context.RequestScoped;
 4import javax.ws.rs.GET;
 5import javax.inject.Inject;
 6import javax.ws.rs.core.Response;
 7import javax.ws.rs.Path;
 8import javax.ws.rs.Produces;
 9import javax.ws.rs.core.MediaType;
10
11@RequestScoped
12@Path("properties")
13public class SystemResource {
14
15  @Inject
16  SystemConfig systemConfig;
17
18  @GET
19  @Produces(MediaType.APPLICATION_JSON)
20  public Response getProperties() {
21    if (!systemConfig.isInMaintenance()) {
22      return Response.ok(System.getProperties()).build();
23    } else {
24      return Response.status(Response.Status.SERVICE_UNAVAILABLE).build();
25    }
26  }
27}

CustomConfigSource.json

1{"config_ordinal":500,
2"io_openliberty_guides_system_inMaintenance":false}

SystemClient.java

 1package io.openliberty.guides.inventory.client;
 2
 3import java.util.Properties;
 4import java.io.IOException;
 5import javax.enterprise.context.Dependent;
 6import javax.ws.rs.ProcessingException;
 7import javax.ws.rs.GET;
 8import javax.ws.rs.Path;
 9import javax.ws.rs.Produces;
10import javax.ws.rs.core.MediaType;
11import org.eclipse.microprofile.rest.client.annotation.RegisterProvider;
12import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
13
14
15@RegisterRestClient
16@RegisterProvider(ExceptionMapper.class)
17@Path("/properties")
18public interface SystemClient {
19  @GET
20  @Produces(MediaType.APPLICATION_JSON)
21  public Properties getProperties()
22      throws UnknownUrlException, IOException, ProcessingException;
23}

server.xml

 1<server description="Sample Liberty server">
 2
 3  <featureManager>
 4    <feature>jaxrs-2.1</feature>
 5    <feature>jsonp-1.1</feature>
 6    <feature>cdi-2.0</feature>
 7    <feature>mpConfig-1.3</feature>
 8    <feature>mpRestClient-1.2</feature>
 9    <feature>mpFaultTolerance-2.0</feature>
10  </featureManager>
11
12  <httpEndpoint host="*" httpPort="${default.http.port}"
13    httpsPort="${default.https.port}" id="defaultHttpEndpoint"/>
14
15  <webApplication location="microprofile-fallback.war" contextRoot="/"/>
16</server>

pom.xml

  1<?xml version='1.0' encoding='utf-8'?>
  2<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">
  3
  4  <modelVersion>4.0.0</modelVersion>
  5
  6  <parent>
  7    <groupId>net.wasdev.wlp.maven.parent</groupId>
  8    <artifactId>liberty-maven-app-parent</artifactId>
  9    <version>RELEASE</version>
 10  </parent>
 11
 12  <groupId>io.openliberty.guides</groupId>
 13  <artifactId>microprofile-fallback</artifactId>
 14  <version>1.0-SNAPSHOT</version>
 15  <packaging>war</packaging>
 16
 17  <properties>
 18    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 19    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
 20    <maven.compiler.source>1.8</maven.compiler.source>
 21    <maven.compiler.target>1.8</maven.compiler.target>
 22    <app.name>LibertyProject</app.name>
 23    <testServerHttpPort>9080</testServerHttpPort>
 24    <testServerHttpsPort>9443</testServerHttpsPort>
 25    <package.file>${project.build.directory}/${app.name}.zip</package.file>
 26    <packaging.type>usr</packaging.type>
 27  </properties>
 28
 29  <dependencyManagement>
 30      <dependencies>
 31          <dependency>
 32              <groupId>io.openliberty.features</groupId>
 33              <artifactId>features-bom</artifactId>
 34              <version>RELEASE</version>
 35              <type>pom</type>
 36              <scope>import</scope>
 37          </dependency>
 38      </dependencies>
 39  </dependencyManagement>
 40
 41  <dependencies>
 42    <!-- Open Liberty features -->
 43    <dependency>
 44        <groupId>io.openliberty.features</groupId>
 45        <artifactId>jaxrs-2.1</artifactId>
 46        <type>esa</type>
 47        <scope>provided</scope>
 48    </dependency>
 49    <dependency>
 50        <groupId>io.openliberty.features</groupId>
 51        <artifactId>jsonp-1.1</artifactId>
 52        <type>esa</type>
 53        <scope>provided</scope>
 54    </dependency>
 55    <dependency>
 56        <groupId>io.openliberty.features</groupId>
 57        <artifactId>cdi-2.0</artifactId>
 58        <type>esa</type>
 59        <scope>provided</scope>
 60    </dependency>
 61    <dependency>
 62        <groupId>io.openliberty.features</groupId>
 63        <artifactId>mpConfig-1.3</artifactId>
 64        <type>esa</type>
 65        <scope>provided</scope>
 66    </dependency>
 67    <dependency>
 68        <groupId>io.openliberty.features</groupId>
 69        <artifactId>mpRestClient-1.2</artifactId>
 70        <type>esa</type>
 71        <scope>provided</scope>
 72    </dependency>
 73    <dependency>
 74        <groupId>io.openliberty.features</groupId>
 75        <artifactId>mpFaultTolerance-2.0</artifactId>
 76        <type>esa</type>
 77        <scope>provided</scope>
 78    </dependency>
 79    <!-- For tests -->
 80    <dependency>
 81      <groupId>junit</groupId>
 82      <artifactId>junit</artifactId>
 83      <version>4.12</version>
 84      <scope>test</scope>
 85    </dependency>
 86    <dependency>
 87      <groupId>org.apache.cxf</groupId>
 88      <artifactId>cxf-rt-rs-client</artifactId>
 89      <version>3.2.6</version>
 90      <scope>test</scope>
 91    </dependency>
 92    <dependency>
 93      <groupId>org.apache.cxf</groupId>
 94      <artifactId>cxf-rt-rs-extension-providers</artifactId>
 95      <version>3.2.6</version>
 96      <scope>test</scope>
 97    </dependency>
 98    <dependency>
 99      <groupId>org.glassfish</groupId>
100      <artifactId>javax.json</artifactId>
101      <version>1.0.4</version>
102      <scope>test</scope>
103    </dependency>
104    <dependency>
105      <groupId>javax.json.bind</groupId>
106      <artifactId>javax.json.bind-api</artifactId>
107      <version>1.0</version>
108      <scope>test</scope>
109    </dependency>
110    <dependency>
111      <groupId>org.eclipse</groupId>
112      <artifactId>yasson</artifactId>
113      <version>1.0</version>
114      <scope>test</scope>
115    </dependency>
116    <!-- Java utility classes -->
117    <dependency>
118      <groupId>org.apache.commons</groupId>
119      <artifactId>commons-lang3</artifactId>
120      <version>3.0</version>
121    </dependency>
122    <!-- Support for JDK 9 and above -->
123    <dependency>
124        <groupId>javax.xml.bind</groupId>
125        <artifactId>jaxb-api</artifactId>
126        <version>2.3.1</version>
127    </dependency>
128    <dependency>
129        <groupId>com.sun.xml.bind</groupId>
130        <artifactId>jaxb-core</artifactId>
131        <version>2.3.0.1</version>
132    </dependency>
133    <dependency>
134        <groupId>com.sun.xml.bind</groupId>
135        <artifactId>jaxb-impl</artifactId>
136        <version>2.3.2</version>
137    </dependency>
138    <dependency>
139        <groupId>javax.activation</groupId>
140        <artifactId>activation</artifactId>
141        <version>1.1.1</version>
142    </dependency>
143  </dependencies>
144
145  <build>
146    <plugins>
147      <plugin>
148        <groupId>org.apache.maven.plugins</groupId>
149        <artifactId>maven-war-plugin</artifactId>
150        <version>3.2.2</version>
151        <configuration>
152          <failOnMissingWebXml>false</failOnMissingWebXml>
153          <packagingExcludes>pom.xml</packagingExcludes>
154        </configuration>
155      </plugin>
156      <!-- Plugin to run unit tests -->
157      <plugin>
158        <groupId>org.apache.maven.plugins</groupId>
159        <artifactId>maven-surefire-plugin</artifactId>
160        <version>3.0.0-M1</version>
161        <executions>
162          <execution>
163            <phase>test</phase>
164            <id>default-test</id>
165            <configuration>
166              <excludes>
167                <exclude>**/it/**</exclude>
168              </excludes>
169              <reportsDirectory>
170                ${project.build.directory}/test-reports/unit
171              </reportsDirectory>
172            </configuration>
173          </execution>
174        </executions>
175      </plugin>
176      <!-- Enable liberty-maven plugin -->
177      <plugin>
178        <groupId>net.wasdev.wlp.maven.plugins</groupId>
179        <artifactId>liberty-maven-plugin</artifactId>
180        <!-- <version>2.6.1</version> -->
181        <configuration>
182          <assemblyArtifact>
183            <groupId>io.openliberty</groupId>
184            <artifactId>openliberty-runtime</artifactId>
185            <version>RELEASE</version>
186            <type>zip</type>
187          </assemblyArtifact>
188          <configFile>src/main/liberty/config/server.xml</configFile>
189          <packageFile>${package.file}</packageFile>
190          <include>${packaging.type}</include>
191          <bootstrapProperties>
192            <default.http.port>${testServerHttpPort}</default.http.port>
193            <default.https.port>${testServerHttpsPort}</default.https.port>
194          </bootstrapProperties>
195        </configuration>
196        <executions>
197          <execution>
198            <id>install-apps</id>
199            <configuration>
200              <looseApplication>true</looseApplication>
201              <stripVersion>true</stripVersion>
202              <installAppPackages>project</installAppPackages>
203            </configuration>
204          </execution>
205          <execution>
206            <id>package-server</id>
207            <configuration>
208              <outputDirectory>target/wlp-package</outputDirectory>
209            </configuration>
210          </execution>
211        </executions>
212      </plugin>
213      <!-- Plugin to run functional tests -->
214      <plugin>
215        <groupId>org.apache.maven.plugins</groupId>
216        <artifactId>maven-failsafe-plugin</artifactId>
217        <version>3.0.0-M1</version>
218        <executions>
219          <execution>
220            <phase>integration-test</phase>
221            <id>integration-test</id>
222            <goals>
223              <goal>integration-test</goal>
224            </goals>
225            <configuration>
226              <runOrder>reversealphabetical</runOrder>
227              <includes>
228                <include>**/it/**/*.java</include>
229              </includes>
230              <systemPropertyVariables>
231                <liberty.test.port>${testServerHttpPort}</liberty.test.port>
232              </systemPropertyVariables>
233            </configuration>
234          </execution>
235          <execution>
236            <id>verify-results</id>
237            <goals>
238              <goal>verify</goal>
239            </goals>
240          </execution>
241        </executions>
242        <configuration>
243          <summaryFile>
244            ${project.build.directory}/test-reports/it/failsafe-summary.xml
245          </summaryFile>
246          <reportsDirectory>${project.build.directory}/test-reports/it</reportsDirectory>
247        </configuration>
248      </plugin>
249    </plugins>
250  </build>
251</project>

Adding the @Fallback annotation

The inventory service is now able to recognize that the system service was taken down for maintenance. An IOException is thrown to simulate the system service is unavailable. Now, set a fallback method to deal with this failure.

Create the InventoryManager class.
src/main/java/io/openliberty/guides/inventory/InventoryManager.java

InventoryManager.java

 1package io.openliberty.guides.inventory;
 2
 3import java.io.IOException;
 4import java.util.Properties;
 5import java.util.ArrayList;
 6import java.util.Collections;
 7import java.util.List;
 8import javax.enterprise.context.ApplicationScoped;
 9import org.eclipse.microprofile.faulttolerance.Fallback;
10import io.openliberty.guides.inventory.model.*;
11
12@ApplicationScoped
13public class InventoryManager {
14
15  private List<SystemData> systems = Collections.synchronizedList(new ArrayList<>());
16  private InventoryUtils invUtils = new InventoryUtils();
17
18  @Fallback(fallbackMethod = "fallbackForGet")
19  public Properties get(String hostname) throws IOException {
20    return invUtils.getProperties(hostname);
21  }
22
23  public Properties fallbackForGet(String hostname) {
24    Properties properties = findHost(hostname);
25    if (properties == null) {
26      Properties msgProp = new Properties();
27      msgProp.setProperty(hostname, "System is not found in the inventory");
28      return msgProp;
29    }
30    return properties;
31  }
32
33  public void add(String hostname, Properties systemProps) {
34    Properties props = new Properties();
35    props.setProperty("os.name", systemProps.getProperty("os.name"));
36    props.setProperty("user.name", systemProps.getProperty("user.name"));
37
38    SystemData system = new SystemData(hostname, props);
39    if (!systems.contains(system)) {
40      systems.add(system);
41    }
42  }
43
44  public InventoryList list() {
45    return new InventoryList(systems);
46  }
47
48  private Properties findHost(String hostname) {
49    for (SystemData system : systems) {
50      if (system.getHostname().equals(hostname)) {
51        return system.getProperties();
52      }
53    }
54    return null;
55  }
56}

The @Fallback annotation dictates a method to call when the original method encounters a failed execution. In this example, use the fallbackForGet() method.

The fallbackForGet() method, which is the designated fallback method for the original get() method, checks to see if the system’s properties exist in the inventory. If the system properties entry is not found in the inventory, the method prints out a warning message in the browser. Otherwise, this method returns the cached property values from the inventory.

You successfully set up your microservice to have fault tolerance capability.

Building and running the application

To build the application, run the Maven install phase from the command line in the start directory:

mvn install

This command builds the application and creates a .war file in the target directory. It also configures and installs Open Liberty into the target/liberty/wlp directory.

Next, run the Maven liberty:start-server goal:

mvn liberty:start-server

This goal starts an Open Liberty server instance. Your Maven pom.xml is already configured to start the application in this server instance.

When the server is running, point your browser to the http://localhost:9080/inventory/systems/localhost URL. You receive the system properties of your local JVM from the inventory service. Next, point your browser to the system service URL, which is located at http://localhost:9080/system/properties, to retrieve the system properties for the specific localhost. Notice that the results from the two URLs are identical because the inventory service gets its results from calling the system service.

Update the configuration file.
resources/CustomConfigSource.json

CustomConfigSource.json

1{"config_ordinal":500,
2"io_openliberty_guides_system_inMaintenance":false}

InventoryManager.java

 1package io.openliberty.guides.inventory;
 2
 3import java.io.IOException;
 4import java.util.Properties;
 5import java.util.ArrayList;
 6import java.util.Collections;
 7import java.util.List;
 8import javax.enterprise.context.ApplicationScoped;
 9import org.eclipse.microprofile.faulttolerance.Fallback;
10import io.openliberty.guides.inventory.model.*;
11
12@ApplicationScoped
13public class InventoryManager {
14
15  private List<SystemData> systems = Collections.synchronizedList(new ArrayList<>());
16  private InventoryUtils invUtils = new InventoryUtils();
17
18  @Fallback(fallbackMethod = "fallbackForGet")
19  public Properties get(String hostname) throws IOException {
20    return invUtils.getProperties(hostname);
21  }
22
23  public Properties fallbackForGet(String hostname) {
24    Properties properties = findHost(hostname);
25    if (properties == null) {
26      Properties msgProp = new Properties();
27      msgProp.setProperty(hostname, "System is not found in the inventory");
28      return msgProp;
29    }
30    return properties;
31  }
32
33  public void add(String hostname, Properties systemProps) {
34    Properties props = new Properties();
35    props.setProperty("os.name", systemProps.getProperty("os.name"));
36    props.setProperty("user.name", systemProps.getProperty("user.name"));
37
38    SystemData system = new SystemData(hostname, props);
39    if (!systems.contains(system)) {
40      systems.add(system);
41    }
42  }
43
44  public InventoryList list() {
45    return new InventoryList(systems);
46  }
47
48  private Properties findHost(String hostname) {
49    for (SystemData system : systems) {
50      if (system.getHostname().equals(hostname)) {
51        return system.getProperties();
52      }
53    }
54    return null;
55  }
56}

You can test the fault tolerance mechanism of your microservices by dynamically changing the io_openliberty_guides_system_inMaintenance property value to true in the resources/CustomConfigSource.json file, which turns the system service in maintenance. After saving the file, go back to your browser and refresh to the http://localhost:9080/inventory/systems/localhost URL to view the cached version of the properties. The fallbackForGet() method, which is the designated fallback method, is called when the system service is not available. The cached system properties contain only the OS name and user name key and value pairs.

To see that the system service is down, point your browser to the http://localhost:9080/system/properties URL again. You see that the service displays a 503 HTTP response code.

When you’re done, change the io_openliberty_guides_system_inMaintenance property value back to false in the resources/CustomConfigSource.json file.

If you make changes to the code, use the Maven compile goal to rebuild the application and have the running Open Liberty server pick them up automatically:

mvn compile

To stop the Open Liberty server, run the Maven liberty:stop-server goal:

mvn liberty:stop-server

Testing the application

You can test your application manually, but automated tests ensure code quality because they trigger a failure whenever a code change introduces a defect. JUnit and the JAX-RS Client API provide a simple environment for you to write tests.

Create the FaultToleranceTest class.
src/test/java/it/io/openliberty/guides/faulttolerance/FaultToleranceTest.java

The @Before and @After annotations indicate that this method executes before or after the other test case. These methods are generally used to perform any setup and teardown tasks. In this case, the setup method creates a JAX-RS client, which makes HTTP requests to the inventory service. This client must also be registered with a JSON-P provider to process JSON resources. The teardown method simply destroys this client instance as well as the HTTP responses.

The testFallbackForGet() test case sends a request to the inventory service to get the systems properties for a host name before and after the system service becomes unavailable. Then, it asserts outputs from the two requests to ensure that they are different from each other.

The @Test annotation indicates that the method automatically executes when your test class runs.

In addition, a few endpoint tests have been included for you to test the basic functionality of the inventory and system services. If a test failure occurs, then you might have introduced a bug into the code.

FaultToleranceTest.java

 1package it.io.openliberty.guides.faulttolerance;
 2
 3import static org.junit.Assert.assertEquals;
 4import static org.junit.Assert.assertTrue;
 5import javax.json.JsonObject;
 6import javax.ws.rs.client.Client;
 7import javax.ws.rs.client.ClientBuilder;
 8import javax.ws.rs.core.Response;
 9import org.apache.cxf.jaxrs.provider.jsrjsonp.JsrJsonpProvider;
10import org.junit.After;
11import org.junit.Before;
12import org.junit.Test;
13
14import it.io.openliberty.guides.utils.TestUtils;
15
16public class FaultToleranceTest {
17
18    private Response response;
19    private Client client;
20
21    @Before
22    public void setup() {
23        client = ClientBuilder.newClient();
24        client.register(JsrJsonpProvider.class);
25    }
26
27    @After
28    public void teardown() {
29        client.close();
30        response.close();
31    }
32
33    @Test
34    public void testFallbackForGet() throws InterruptedException {
35        response = TestUtils.getResponse(client,
36                                         TestUtils.INVENTORY_LOCALHOST_URL);
37        assertResponse(TestUtils.baseUrl, response);
38        JsonObject obj = response.readEntity(JsonObject.class);
39        int propertiesSize = obj.size();
40        TestUtils.changeSystemProperty(TestUtils.SYSTEM_MAINTENANCE_FALSE,
41                                       TestUtils.SYSTEM_MAINTENANCE_TRUE);
42        Thread.sleep(3000);
43        response = TestUtils.getResponse(client,
44                                         TestUtils.INVENTORY_LOCALHOST_URL);
45        assertResponse(TestUtils.baseUrl, response);
46        obj = response.readEntity(JsonObject.class);
47        int propertiesSizeFallBack = obj.size();
48        assertTrue("The total number of properties from the @Fallback method "
49                + "is not smaller than the number from the system service, as expected.",
50                   propertiesSize > propertiesSizeFallBack);
51        TestUtils.changeSystemProperty(TestUtils.SYSTEM_MAINTENANCE_TRUE,
52                                       TestUtils.SYSTEM_MAINTENANCE_FALSE);
53    }
54
55    private void assertResponse(String url, Response response) {
56        assertEquals("Incorrect response code from " + url, 200,
57                     response.getStatus());
58    }
59}

Running the tests

If the server is still running from the previous steps, stop it using the Maven liberty:stop-server goal from command line in the start directory:

mvn liberty:stop-server

Then, verify that the tests pass using the Maven verify goal:

mvn verify

It may take some time before build is complete. If the tests pass, you will see a similar output to the following:

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running it.io.openliberty.guides.system.SystemEndpointTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.937 sec - in it.io.openliberty.guides.system.SystemEndpointTest
Running it.io.openliberty.guides.inventory.InventoryEndpointTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.396 sec - in it.io.openliberty.guides.inventory.InventoryEndpointTest
Running it.io.openliberty.guides.faulttolerance.FaultToleranceTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 3.517 sec - in it.io.openliberty.guides.faulttolerance.FaultToleranceTest

Results :

Tests run: 3, Failures: 0, Errors: 0, Skipped: 0

To see if the tests detect a failure, comment out the changeSystemProperty() methods in the FaultToleranceTest.java file. Rerun the Maven build. You see a test failure occur for the testFallbackForGet() test case.

Great work! You’re done!

You just learned how to build a fallback mechanism for a microservice with MicroProfile Fault Tolerance in Open Liberty and wrote a test to validate it.

You can try one of the related MicroProfile guides. They demonstrate technologies that you can learn and expand on what you built here.

Guide Attribution

Building fault-tolerant microservices with the @Fallback annotation by Open Liberty is licensed under CC BY-ND 4.0

Copied to clipboard
Copy code block
Copy file contents
Git clone this repo to get going right away:
git clone https://github.com/OpenLiberty/guide-microprofile-fallback.git
Copy github clone command
Copied to clipboard

Nice work! Where to next?

What could make this guide better?

Raise an issue to share feedback

Create a pull request to contribute to this guide

Need help?

Ask a question on Stack Overflow

What did you think of this guide?

Extreme Dislike Dislike Like Extreme Like