Building fault-tolerant microservices with the @Fallback annotation
|This repository contains the guide documentation source. To view the guide in published form, view it on the Open Liberty website.|
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
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.
Try what you’ll build
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 clean 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.
Now, open the
resources/CustomConfigSource.json file and change the
io_openliberty_guides_system_inMaintenance property from
true and save the file. You do not need
to restart the server. Next, return to your browser and point back to the
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 and
io_openliberty_guides_system_inMaintenance property from
false to set this
condition back to its original value.
Stop the Open Liberty 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
src/main/java/io/openliberty/guides/system/SystemResource.java class has
isInMaintenance() condition, which determines that the system properties are returned only if you
io_openliberty_guides_system_inMaintenance configuration property
false in the
Otherwise, the service returns a
Status.SERVICE_UNAVAILABLE message, which makes it unavailable.
makes a request to the
system service and checks for the response.
system service 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.
getProperties() method in this class calls the
InventoryManager class calls this public method.
You will look into the
InventoryManager class in more detail in the next section.
Adding the @Fallback annotation
inventory service is now able to recognize that the
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.
InventoryManager class in the
@Fallback annotation dictates a method to call when the original method encounters a failed execution. In this
example, use 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.
When the server is running, point your browser to the
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
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
You can test the fault tolerance mechanism of your microservices by dynamically changing
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
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
property value back to
false in the
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.
FaultToleranceTest class in the
@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.
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.
@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
system services. If a test failure occurs, then you might have introduced a bug into
------------------------------------------------------- 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
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 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.