An open API service indexing awesome lists of open source software.

https://github.com/vertx-howtos/resilience4j-howto

Using Resilience4j with Vert.x
https://github.com/vertx-howtos/resilience4j-howto

circuit-breaker howto resilience4j vertx

Last synced: 13 days ago
JSON representation

Using Resilience4j with Vert.x

Awesome Lists containing this project

README

        

// suppress inspection "GrazieInspection" for whole file
= Using Resilience4j with Vert.x
:page-permalink: /
:page-github: vertx-howtos/resilience4j-howto

ifdef::env-github[]
image:https://github.com/vertx-howtos/resilience4j-howto/workflows/Publish%20the%20how-to/badge.svg["Build Status", link="https://github.com/vertx-howtos/resilience4j-howto/actions?query=workflow%3A%22Publish+the+how-to%22"]
endif::env-github[]

This document will show you how to use Resilience4j in Vert.x applications.

link:https://resilience4j.readme.io/[Resilience4j] is a popular library that implements common fault tolerance strategies:

* bulkhead (concurrency limiter)
* circuit breaker
* rate limiter
* retry
* time limiter (timeout)

In this how-to, we only demonstrate the usage of a circuit breaker, but the repository of this how-to contains Vert.x adapters for all strategies mentioned above.

WARNING: Resilience4j 2.0, which we'll use here, requires Java 17.

== What you will build

You will use a circuit breaker with an HTTP client to prevent executing requests against a server that keeps returning errors.
This serves two main purposes:

* avoid generating more load on a server that may be overloaded,
* failing fast when failure is very likely to occur anyway.

The application consists of a few classes:

. the `CircuitBreakerVerticle` class
. the `VertxCircuitBreaker` adapter, which is included in the repository of this how-to

== What you need

* A text editor or IDE
* Java 17 or higher
* Maven or Gradle

== Create a project

The code of this project contains Maven and Gradle build files that are functionally equivalent.

=== Using Maven

First, your `pom.xml` file should declare version properties:

ifdef::env-github[]
link:pom.xml[Maven POM file]
endif::env-github[]
ifndef::env-github[]
[source,xml,indent=0]
.Maven `pom.xml`: version properties
----
include::pom.xml[tag=versions]
----
endif::env-github[]

Next, import the Resilience4j and Vert.x BOMs to manage dependency versions:

ifdef::env-github[]
link:pom.xml[Maven POM file]
endif::env-github[]
ifndef::env-github[]
[source,xml,indent=0]
.Maven `pom.xml`: BOM imports
----
include::pom.xml[tag=bom]
----
endif::env-github[]

Then, add a dependency on the Resilience4j circuit breaker library:

ifdef::env-github[]
link:pom.xml[Maven POM file]
endif::env-github[]
ifndef::env-github[]
[source,xml,indent=0]
.Maven `pom.xml`: Resilience4j dependency
----
include::pom.xml[tag=dependency-resilience4j]
----
endif::env-github[]

Finally, add dependencies on the Vert.x Web and Vert.x Web Client libraries:

ifdef::env-github[]
link:pom.xml[Maven POM file]
endif::env-github[]
ifndef::env-github[]
[source,xml,indent=0]
.Maven `pom.xml`: Vert.x dependencies
----
include::pom.xml[tag=dependency-vertx]
----
endif::env-github[]

=== Using Gradle

The `dependencies` block in your `build.gradle.kts` file (assuming you use Gradle with the Kotlin DSL) should first import the Resilience4j and Vert.x BOMs to manage dependency versions:

ifdef::env-github[]
link:build.gradle.kts[Gradle build file]
endif::env-github[]
ifndef::env-github[]
[source,kotlin,indent=0]
.Gradle `build.gradle.kts`: BOM imports
----
include::build.gradle.kts[tag=bom]
----
endif::env-github[]

Then, add a dependency on the Resilience4j circuit breaker library:

ifdef::env-github[]
link:build.gradle.kts[Gradle build file]
endif::env-github[]
ifndef::env-github[]
[source,kotlin,indent=0]
.Gradle `build.gradle.kts`: Resilience4j dependency
----
include::build.gradle.kts[tag=dependency-resilience4j]
----
endif::env-github[]

Finally, add dependencies on the Vert.x Web and Vert.x Web Client libraries:

ifdef::env-github[]
link:build.gradle.kts[Gradle build file]
endif::env-github[]
ifndef::env-github[]
[source,kotlin,indent=0]
.Gradle `build.gradle.kts`: Vert.x dependencies
----
include::build.gradle.kts[tag=dependency-vertx]
----
endif::env-github[]

== Using circuit breaker to guard Vert.x Web Client requests

First, let's create the main `CircuitBreakerVerticle` class:

ifdef::env-github[]
link:src/main/java/io/vertx/howtos/resilience4j/CircuitBreakerVerticle.java[The `CircuitBreakerVerticle` class]
endif::env-github[]
ifndef::env-github[]
[source,java,indent=0]
.The `CircuitBreakerVerticle` class
----
include::src/main/java/io/vertx/howtos/resilience4j/CircuitBreakerVerticle.java[tag=class]
----
endif::env-github[]

This class will use the `VertxCircuitBreaker` class, which is provided in the repository of this how-to.

=== Creating the circuit breaker

In the `start` method of the verticle, let's create a single circuit breaker instance that will be shared among all requests.
For demonstration purposes, we will configure the circuit breaker to start calculating the failure rate after mere 5 requests:

ifdef::env-github[]
link:src/main/java/io/vertx/howtos/resilience4j/CircuitBreakerVerticle.java[The `CircuitBreakerVerticle` class]
endif::env-github[]
ifndef::env-github[]
[source,java,indent=0]
.Create the circuit breaker
----
include::src/main/java/io/vertx/howtos/resilience4j/CircuitBreakerVerticle.java[tag=circuit-breaker]
----
endif::env-github[]

TIP: The default settings make a lot more sense for a real-world application than our demonstration configuration.

=== Creating a server

Next, we'll use Vert.x Web to expose a simple endpoint.
The sole purpose of that endpoint will be to perform an HTTP request and guard it with the circuit breaker:

ifdef::env-github[]
link:src/main/java/io/vertx/howtos/resilience4j/CircuitBreakerVerticle.java[The `CircuitBreakerVerticle` class]
endif::env-github[]
ifndef::env-github[]
[source,java,indent=0]
.Create the endpoint
----
include::src/main/java/io/vertx/howtos/resilience4j/CircuitBreakerVerticle.java[tag=router]
----
endif::env-github[]

This deserves some explanation.

The endpoint on `/` uses the `VertxCircuitBreaker` adapter that glues together the Resilience4j API and Vert.x ``Future``s.
The adapter expects a `Supplier` as an action to be guarded.

The `Future` here comes from the Vert.x Web Client `get(8080, "localhost", "/does-not-exist")` call.

As you can imagine, the request we make here will never succeed.
Therefore, the circuit breaker will kick in after 5 requests (as configured above) and will prevent further calls to the guarded action.
Instead, the `Future` returned by `executeFuture` will fail instantly with the `CallNotPermittedException` exception.

=== Starting the server

Finally, we'll start the server:

ifdef::env-github[]
link:src/main/java/io/vertx/howtos/resilience4j/CircuitBreakerVerticle.java[The `CircuitBreakerVerticle` class]
endif::env-github[]
ifndef::env-github[]
[source,java,indent=0]
.Start the server
----
include::src/main/java/io/vertx/howtos/resilience4j/CircuitBreakerVerticle.java[tag=server]
----
endif::env-github[]

The entire `start` method of the verticle looks like this:

ifdef::env-github[]
link:src/main/java/io/vertx/howtos/resilience4j/CircuitBreakerVerticle.java[The `CircuitBreakerVerticle` class]
endif::env-github[]
ifndef::env-github[]
[source,java,indent=0]
.The `start` method of the verticle
----
include::src/main/java/io/vertx/howtos/resilience4j/CircuitBreakerVerticle.java[tag=start]
----
endif::env-github[]

== Running the application

The `CircuitBreakerVerticle` also needs a `main` method:

ifdef::env-github[]
link:src/main/java/io/vertx/howtos/resilience4j/CircuitBreakerVerticle.java[The `CircuitBreakerVerticle` class]
endif::env-github[]
ifndef::env-github[]
[source,java,indent=0]
.The `main` method
----
include::src/main/java/io/vertx/howtos/resilience4j/CircuitBreakerVerticle.java[tag=main]
----
endif::env-github[]

Then you can run the application:

* straight from your IDE, or
* with Maven: `mvn clean compile exec:java`, or
* with Gradle: `./gradlew run` (Linux, macOS) or `gradlew run` (Windows).

The following examples use the https://httpie.org/[HTTPie] command line HTTP client.
Please refer to the https://httpie.org/doc#installation[installation] documentation if you don't have it installed on your system yet.

=== First 5 requests

For the first 5 requests, the circuit breaker does not calculate the failure rate and will allow all actions to proceed.
As expected, they will all fail:

[source,shell]
----
http localhost:8080
http localhost:8080
http localhost:8080
http localhost:8080
http localhost:8080
----

You should see the following output 5 times:

[source,text]
----
Failed with: io.vertx.core.impl.NoStackTraceThrowable: Response status code 404 is not between 200 and 300
----

=== Next, the circuit breaker kicks in

[source,shell]
----
http localhost:8080
----

The 6th request will fail with a different message:

[source,text]
----
Failed with: io.github.resilience4j.circuitbreaker.CallNotPermittedException: CircuitBreaker 'my-circuit-breaker' is OPEN and does not permit further calls
----

We see that the circuit breaker prevented the execution of the request against the server.

== Summary

This document covered:

. creating an instance of the Resilience4j circuit breaker,
. using the circuit breaker to guard an action whose result is a Vert.x `Future`.

== See also

* link:https://resilience4j.readme.io/[The Resilience4j documentation]