= Vert.x Service Discovery

This component provides an infrastructure to publish and discover various resources, such as service
proxies, HTTP endpoints, data sources... These resources are called `services`. A `service` is a discoverable
functionality. It can be qualified by its type, metadata, and location. So a `service` can be a database, a
service proxy, a HTTP endpoint and any other resource you can imagine as soon as you can describe it, discover it
and interact with it. It does not have to be a vert.x entity, but can be anything. Each service is described by a
{@link io.vertx.servicediscovery.Record}.

The service discovery implements the interactions defined in service-oriented computing. And to some extent,
also provides the dynamic service-oriented computing interactions. So, applications can react to arrival and
departure of services.

A service provider can:

* publish a service record
* un-publish a published record
* update the status of a published service (down, out of service...)

A service consumer can:

* lookup services
* bind to a selected service (it gets a {@link io.vertx.servicediscovery.ServiceReference}) and use it
* release the service once the consumer is done with it
* listen for arrival, departure and modification of services.

Consumer would 1) lookup a service record matching their need, 2) retrieve the
{@link io.vertx.servicediscovery.ServiceReference} that give access to the service, 3) get a service object to access
the service, 4) release the service object once done.

The process can be simplified using _service type_ where you can directly retrieve the service object if you know
from which type it is (JDBC client, Http client...).

As stated above, the central piece of information shared by the providers and consumers are
{@link io.vertx.servicediscovery.Record records}.

Providers and consumers must create their own {@link io.vertx.servicediscovery.ServiceDiscovery} instance. These
instances are collaborating in the background (distributed structure) to keep the set of services in sync.

The service discovery supports bridges to import and export services from / to other discovery technologies.

== Using the service discovery

To use the Vert.x service discovery, add the following dependency to the _dependencies_ section of your build
descriptor:

* Maven (in your `pom.xml`):

[source,xml,subs="+attributes"]
----
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-service-discovery</artifactId>
<version>${maven.version}</version>
</dependency>
----

* Gradle (in your `build.gradle` file):

[source,groovy,subs="+attributes"]
----
compile 'io.vertx:vertx-service-discovery:${maven.version}'
----

== Overall concepts

The discovery mechanism is based on a few concepts explained in this section.

=== Service records

A service {@link io.vertx.servicediscovery.Record} is an object that describes a service published by a service
provider. It contains a name, some metadata, a location object (describing where is the service). This record is
the only object shared by the provider (having published it) and the consumer (retrieve it when doing a lookup).

The metadata and even the location format depend on the `service type` (see below).

A record is published when the provider is ready to be used, and withdrawn when the service provider is stopping.

=== Service Provider and publisher

A service provider is an entity providing a _service_. The publisher is responsible for publishing a record
describing the provider. It may be a single entity (a provider publishing itself) or a different entity.

=== Service Consumer

Service consumers search for services in the service discovery. Each lookup retrieves `0..n`
{@link io.vertx.servicediscovery.Record}. From these records, a consumer can retrieve a
{@link io.vertx.servicediscovery.ServiceReference}, representing the binding between the consumer and the provider.
This reference allows the consumer to retrieve the _service object_ (to use the service),  and release the service.

It is important to release service references to cleanup the objects and update the service usages.

=== Service object

The service object is the object that gives access to a service. It can come in various forms, such as a proxy, a client,
and may even be non-existent for some service types. The nature of the service object depends on the service type.

Notice that because of the polyglot nature of Vert.x, the service object can differ if you retrieve it from Java,
Groovy or another language.

=== Service types

Services are just resources, and there are a lot of different kinds of services. They can be functional services,
databases, REST APIs, and so on. The Vert.x service discovery has the concept of service types to handle this
heterogeneity. Each type defines:

* how the service is located (URI, event bus address, IP / DNS...) - _location_
* the nature of the service object (service proxy, HTTP client, message consumer...) - _client_

Some service types are implemented and provided by the service discovery component, but you can add
your own.

=== Service events

Every time a service provider is published or withdrawn, an event is fired on the event bus. This event contains
the record that has been modified.

In addition, in order to track who is using who, every time a reference is retrieved with
{@link io.vertx.servicediscovery.ServiceDiscovery#getReference(Record)} or released with
{@link io.vertx.servicediscovery.ServiceReference#release()}, events are emitted on the event bus to track the
service usages.

More details on these events below.

=== Backend

The service discovery uses a Vert.x distributed data structure to store the records. So, all members of the cluster
have access to all the records. This is the default backend implementation. You can implement your own by
implementing the {@link io.vertx.servicediscovery.spi.ServiceDiscoveryBackend} SPI. For instance, we provide an
implementation based on Redis.

Notice that the discovery does not require Vert.x clustering. In single-node mode, the structure is local. It can
be populated with {@link io.vertx.servicediscovery.spi.ServiceImporter}s. Since 3.5.0, you can use a local
structure even in clustered mode by setting the system property `vertx-service-discovery-backend-local` to `true` (or
the environment variable `VERTX-SERVICE-DISCOVERY-BACKEND-LOCAL` to `true`).

== Creating a service discovery instance

Publishers and consumers must create their own {@link io.vertx.servicediscovery.ServiceDiscovery}
instance to use the discovery infrastructure:

[source,$lang]
----
{@link examples.ServiceDiscoveryExamples#example1(io.vertx.core.Vertx)}
----

By default, the announce address (the event bus address on which service events are sent is: `vertx.discovery
.announce`. You can also configure a name used for the service usage (see section about service usage).

When you don't need the service discovery object anymore, don't forget to close it. It closes the different
discovery importers and exporters you have configured and releases the service references.

You should avoid sharing the service discovery instance, so service usage would represent the right "usages".

== Publishing services

Once you have a service discovery instance, you can publish services. The process is the following:

1. create a record for a specific service provider
2. publish this record
3. keep the published record that is used to un-publish a service or modify it.

To create records, you can either use the {@link io.vertx.servicediscovery.Record} class, or use convenient methods
from the service types.

[source,$lang]
----
{@link examples.ServiceDiscoveryExamples#example2(ServiceDiscovery)}
----

It is important to keep a reference on the returned records, as this record has been extended by a `registration id`.

== Withdrawing services

To withdraw (un-publish) a record, use:

[source,$lang]
----
{@link examples.ServiceDiscoveryExamples#example3(ServiceDiscovery, Record)}
----

== Looking for services

_This section explains the low-level process to retrieve services, each service type provide convenient method to
aggregates the different steps._

On the consumer side, the first thing to do is to lookup for records. You can search for a single record or all
the matching ones. In the first case, the first matching record is returned.

Consumer can pass a filter to select the service. There are two ways to describe the filter:

1. A function taking a {@link io.vertx.servicediscovery.Record} as parameter and returning a boolean (it's a
predicate)
2. This filter is a JSON object. Each entry of the given filter is checked against the record. All entries must
exactly match the record. The entry can use the special `*` value to denote a requirement on the key, but not on
the value.

Let's see an example of a JSON filter:
----
{ "name" = "a" } => matches records with name set to "a"
{ "color" = "*" } => matches records with "color" set
{ "color" = "red" } => only matches records with "color" set to "red"
{ "color" = "red", "name" = "a"} => only matches records with name set to "a", and color set to "red"
----

If the JSON filter is not set (`null` or empty), it accepts all records. When using functions, to accept all
records, you must return _true_ regardless the record.

Here are some examples:

[source,$lang]
----
{@link examples.ServiceDiscoveryExamples#example4(ServiceDiscovery)}
----

You can retrieve a single record or all matching records with
{@link io.vertx.servicediscovery.ServiceDiscovery#getRecords(io.vertx.core.json.JsonObject, io.vertx.core.Handler)}.
By default, record lookup does include only records with a `status` set to `UP`. This can be overridden:

* when using JSON filter, just set `status` to the value you want (or `*` to accept all status)
* when using function, set the `includeOutOfService` parameter to `true` in
{@link io.vertx.servicediscovery.ServiceDiscovery#getRecords(java.util.function.Function, boolean, io.vertx.core.Handler)}
.

== Retrieving a service reference

Once you have chosen the {@link io.vertx.servicediscovery.Record}, you can retrieve a
{@link io.vertx.servicediscovery.ServiceReference} and then the service object:

[source,$lang]
----
{@link examples.ServiceDiscoveryExamples#example5(ServiceDiscovery, Record, Record)}
----

Don't forget to release the reference once done.

The service reference represents a binding with the service provider.

When retrieving a service reference you can pass a {@link io.vertx.core.json.JsonObject} used to configure the
service object. It can contain various data about the service object. Some service types do not need additional
configuration, some require configuration (as data sources):

[source,$lang]
----
{@link examples.ServiceDiscoveryExamples#example51(ServiceDiscovery, Record, io.vertx.core.json.JsonObject)}
----

In the previous examples, the code uses
{@link io.vertx.servicediscovery.ServiceReference#getAs(java.lang.Class)}. The parameter is the type of
object you expect to get. If you are using Java, you can use
{@link io.vertx.servicediscovery.ServiceReference#get()}. However in the other language you must pass the expected
type.

== Types of services

A said above, the service discovery has the service type concept to manage the heterogeneity of the
different services.

These types are provided by default:

* {@link io.vertx.servicediscovery.types.HttpEndpoint} - for REST API's, the service object is a
{@link io.vertx.core.http.HttpClient} configured on the host and port (the location is the url).
* {@link io.vertx.servicediscovery.types.EventBusService} - for service proxies, the service object is a proxy. Its
type is the proxies interface (the location is the address).
* {@link io.vertx.servicediscovery.types.MessageSource} - for message sources (publisher), the service object is a
{@link io.vertx.core.eventbus.MessageConsumer} (the location is the address).
* {@link io.vertx.servicediscovery.types.JDBCDataSource} - for JDBC data sources, the service object is a
{@link io.vertx.ext.jdbc.JDBCClient} (the configuration of the client is computed from the location, metadata and
consumer configuration).
* {@link io.vertx.servicediscovery.types.RedisDataSource} - for Redis data sources, the service object is a
{@link io.vertx.redis.client.Redis} (the configuration of the client is computed from the location, metadata and
consumer configuration).
* {@link io.vertx.servicediscovery.types.MongoDataSource} - for Mongo data sources, the service object is a
{@link io.vertx.ext.mongo.MongoClient} (the configuration of the client is computed from the location, metadata and
consumer configuration).

This section gives details about service types in general and describes how to use the default service types.

=== Services with no type

Some records may have no type ({@link io.vertx.servicediscovery.spi.ServiceType#UNKNOWN}). It is not possible to
retrieve a reference for these records, but you can build the connection details from the `location` and
`metadata` of the {@link io.vertx.servicediscovery.Record}.

Using these services does not fire service usage events.

[language, java]
----
=== Implementing your own service type

You can create your own service type by implementing the {@link io.vertx.servicediscovery.spi.ServiceType} SPI:

1. (optional) Create a public interface extending {@link io.vertx.servicediscovery.spi.ServiceType}. This interface is
only used to provide helper methods to ease the usage of your type such as `createRecord` methods, `getX` where `X`
is the type of service object you retrieve and so on. Check {@link io.vertx.servicediscovery.types.HttpEndpoint} or
{@link io.vertx.servicediscovery.types.MessageSource} for example
2. Create a class implementing {@link io.vertx.servicediscovery.spi.ServiceType} or the interface you created in
step 1. The type has a `name`, and a method to create the {@link io.vertx.servicediscovery.ServiceReference} for this
type. The name must match the `type` field of the {@link io.vertx.servicediscovery.Record} associated with your type.
3. Create a class extending `io.vertx.ext.discovery.types.AbstractServiceReference`. You can parameterize
the class with the type of service object your are going to return. You must implement
`AbstractServiceReference#retrieve()` that creates the service object. This
method is only called once. If your service object needs cleanup, also override
`AbstractServiceReference#onClose()`.
4. Create a `META-INF/services/io.vertx.servicediscovery.spi.ServiceType` file that is packaged in your jar. In this
file, just indicate the fully qualified name of the class created at step 2.
5. Creates a jar containing the service type interface (step 1), the implementation (step 2 and 3) and the
service descriptor file (step 4). Put this jar in the classpath of your application. Here you go, your service
type is now available.
----

=== HTTP endpoints

A HTTP endpoint represents a REST API or a service accessible using HTTP requests. The HTTP endpoint service
objects are {@link io.vertx.core.http.HttpClient} configured with the host, port and ssl.

==== Publishing a HTTP endpoint

To publish a HTTP endpoint, you need a {@link io.vertx.servicediscovery.Record}. You can create the record using
{@link io.vertx.servicediscovery.types.HttpEndpoint#createRecord(java.lang.String, java.lang.String, int, java.lang.String, io.vertx.core.json.JsonObject)}.

The next snippet illustrates hot to create a {@link io.vertx.servicediscovery.Record} from
{@link io.vertx.servicediscovery.types.HttpEndpoint}:

[source, $lang]
----
{@link examples.HTTPEndpointExamples#example1(ServiceDiscovery)}
----

When you run your service in a container or on the cloud, it may not know its public IP and public port, so the
publication must be done by another entity having this info. Generally it's a bridge.

==== Consuming a HTTP endpoint

Once a HTTP endpoint is published, a consumer can retrieve it. The service object is a
{@link io.vertx.core.http.HttpClient} with a port and host configured:

[source, $lang]
----
{@link examples.HTTPEndpointExamples#example2(ServiceDiscovery)}
----

You can also use the
{@link io.vertx.servicediscovery.types.HttpEndpoint#getClient(ServiceDiscovery, io.vertx.core.json.JsonObject, io.vertx.core.Handler)}
method to combine lookup and service retrieval in one call:

[source, $lang]
----
{@link examples.HTTPEndpointExamples#example3(ServiceDiscovery)}
----

In this second version, the service object is released using
{@link io.vertx.servicediscovery.ServiceDiscovery#releaseServiceObject(ServiceDiscovery, java.lang.Object)},
so you don't need to keep the service reference.

Since Vert.x 3.4.0, another client has been provided. This higher-level client, named {@link io.vertx.ext.web.client.WebClient}
tends to be easier to use. You can retrieve a {@link io.vertx.ext.web.client.WebClient} instances using:

[source, $lang]
----
{@link examples.HTTPEndpointExamples#example2_webclient(io.vertx.servicediscovery.ServiceDiscovery)}
----

And, if you prefer the approach using the service type:

[source, $lang]
----
{@link examples.HTTPEndpointExamples#example3_webclient(io.vertx.servicediscovery.ServiceDiscovery)}
----

=== Event bus services

Event bus services are service proxies. They implement async-RPC services on top of the event bus. When retrieving
a service object from an event bus service, you get a service proxy of the right type. You can access helper
methods from {@link io.vertx.servicediscovery.types.EventBusService}.

Notice that service proxies (service implementations and service interfaces) are developed in Java.

==== Publishing an event bus service

To publish an event bus service, you need to create a {@link io.vertx.servicediscovery.Record}:

[source, $lang]
----
{@link examples.EventBusServiceExamples#example1(ServiceDiscovery)}
----

[language, java]
----
You can also pass the service interface as class:

[source, java]
\----
{@link examples.limited.EventBusServiceJavaExamples#example1(ServiceDiscovery)}
\----
----

==== Consuming an event bus service

To consume an event bus service you can either retrieve the record and then get the reference, or use the
{@link io.vertx.servicediscovery.types.EventBusService} interface that combines the two operations in one call.

[language, java]
----

When using the reference, you would do something like:
[source, java]
\----
{@link examples.EventBusServiceExamples#example2(ServiceDiscovery)}
\----

With the {@link io.vertx.servicediscovery.types.EventBusService} class, you can get the proxy as follows:
[source, java]
\----
{@link examples.EventBusServiceExamples#example3(ServiceDiscovery)}
\----
----

[language, js]
----
However, as the service is searched by (Java) interface, you need to specify the type of client you expect.

[source, js]
\----
var ServiceDiscovery = require("vertx-service-discovery-js/service_discovery");
var EventBusService = require("vertx-service-discovery-js/event_bus_service");
var MyService = require("org-acme-js/MyService");
EventBusService.getServiceProxyWithJsonFilter(discovery,
    { "service.interface" : "org.acme.MyService"},
    MyService,
    function (ar, ar_err) {
       if (ar_err == null) {
         var service = ar;

         // Dont' forget to release the service
         ServiceDiscovery.releaseServiceObject(discovery, service);
     }
   });
\----
----

[language, ruby]
----
However, as the service is searched by (Java) interface, you need to specify the type of client you expect.

[source, ruby]
\----
require 'vertx-service-discovery/service_discovery'
require 'vertx-service-discovery/event_bus_service'
require 'org-acme/MyService'
VertxServiceDiscovery::EventBusService.get_service_proxy_with_json_filter(discovery, {
'service.interface' => "org.acme.MyService"
}, Acme::MyService) { |ar_err,ar|
   if (ar_err == nil)
     service = ar

     # Dont' forget to release the service
     VertxServiceDiscovery::ServiceDiscovery.release_service_object(discovery, service)
   end
}
\----
----

[language, groovy]
----
However, as the service is searched by (Java) interface, you need to specify the type of client you expect.

[source, $lang]
\----
{@link examples.EventBusServiceExamples#example31(ServiceDiscovery)}
\----
----

=== Message source

A message source is a component sending messages on the event bus on a specific address. Message source clients are
{@link io.vertx.core.eventbus.MessageConsumer}.

The _location_ or a message source service is the event bus address on which messages are sent.

==== Publishing a message source

As for the other service types, publishing a message source is a 2-step process:

1. create a record, using {@link io.vertx.servicediscovery.types.MessageSource}
2. publish the record

[source, $lang]
----
{@link examples.MessageSourceExamples#example1(ServiceDiscovery)}
----

In the second record, the type of payload is also indicated. This information is optional.

[language, java]
----
In java, you can use {@link java.lang.Class} parameters:

[source, $lang]
\----
{@link examples.limited.MessageSourceExamples#example1(ServiceDiscovery)}
\----
----

==== Consuming a message source

On the consumer side, you can retrieve the record and the reference, or use the
{@link io.vertx.servicediscovery.types.MessageSource} class to retrieve the service is one call.

With the first approach, the code is the following:

[source, $lang]
----
{@link examples.MessageSourceExamples#example2(ServiceDiscovery)}
----

When, using {@link io.vertx.servicediscovery.types.MessageSource}, it becomes:

[source, $lang]
----
{@link examples.MessageSourceExamples#example3(ServiceDiscovery)}
----

=== JDBC Data source

Data sources represents databases or data stores. JDBC data sources are a specialization for databases accessible
using a JDBC driver. The client of a JDBC data source service is a {@link io.vertx.ext.jdbc.JDBCClient}.

==== Publishing a JDBC service

As for the other service types, publishing a JDBC data source is a 2-step process:

1. create a record, using {@link io.vertx.servicediscovery.types.JDBCDataSource}
2. publish the record

[source, $lang]
----
{@link examples.JDBCDataSourceExamples#example1(ServiceDiscovery)}
----

As JDBC data sources can represent a high variety of databases, and their access is often different, the record is
rather unstructured. The `location` is a simple JSON object that should provide the fields to access the data
source (JDBC url, username...). The set of fields may depend on the database but also on the connection pool used
in front.

==== Consuming a JDBC service

As stated in the previous section, how to access a data source depends on the data source itself. To build the
{@link io.vertx.ext.jdbc.JDBCClient}, you can merge configuration: the record location, the metadata and a json object provided by
the consumer:

[source, $lang]
----
{@link examples.JDBCDataSourceExamples#example2(ServiceDiscovery)}
----

You can also use the {@link io.vertx.ext.jdbc.JDBCClient} class to the lookup and retrieval in one call:

[source, $lang]
----
{@link examples.JDBCDataSourceExamples#example3(ServiceDiscovery)}
----

=== Redis Data source

Redis data sources are a specialization for Redis persistence databases.
The client of a Redis data source service is a {@link io.vertx.redis.client.Redis}.

==== Publishing a Redis service

Publishing a Redis data source is a 2-step process:

1. create a record, using {@link io.vertx.servicediscovery.types.RedisDataSource}
2. publish the record

[source, $lang]
----
{@link examples.RedisDataSourceExamples#example1(ServiceDiscovery)}
----

The `location` is a simple JSON object that should provide the fields to access the Redis data
source (url, port...).

==== Consuming a Redis service

As stated in the previous section, how to access a data source depends on the data source itself. To build the
{@link io.vertx.redis.client.Redis}, you can merge configuration: the record location, the metadata and a json object provided by
the consumer:

[source, $lang]
----
{@link examples.RedisDataSourceExamples#example2(ServiceDiscovery)}
----

You can also use the {@link io.vertx.servicediscovery.types.RedisDataSource} class to the lookup and retrieval in one call:

[source, $lang]
----
{@link examples.RedisDataSourceExamples#example3(ServiceDiscovery)}
----

=== Mongo Data source

Mongo data sources are a specialization for MongoDB databases.
The client of a Mongo data source service is a {@link io.vertx.ext.mongo.MongoClient}.

==== Publishing a Mongo service

Publishing a Mongo data source is a 2-step process:

1. create a record, using {@link io.vertx.servicediscovery.types.MongoDataSource}
2. publish the record

[source, $lang]
----
{@link examples.MongoDataSourceExamples#example1(ServiceDiscovery)}
----

The `location` is a simple JSON object that should provide the fields to access the Mongo data
source (url, port...).

==== Consuming a Mongo service

As stated in the previous section, how to access a data source depends on the data source itself. To build the
{@link io.vertx.ext.mongo.MongoClient}, you can merge configuration: the record location, the metadata and a json object
provided by the consumer:

[source, $lang]
----
{@link examples.MongoDataSourceExamples#example2(ServiceDiscovery)}
----

You can also use the {@link io.vertx.servicediscovery.types.MongoDataSource} class to the lookup and retrieval in one call:

[source, $lang]
----
{@link examples.MongoDataSourceExamples#example3(ServiceDiscovery)}
----

== Listening for service arrivals and departures

Every time a provider is published or removed, an event is published on the _vertx.discovery.announce_ address.
This address is configurable from the {@link io.vertx.servicediscovery.ServiceDiscoveryOptions}.

The received record has a `status` field indicating the new state of the record:

* `UP` : the service is available, you can start using it
* `DOWN` : the service is not available anymore, you should not use it anymore
* `OUT_OF_SERVICE` : the service is not running, you should not use it anymore, but it may come back later.

== Listening for service usage

Every time a service reference is retrieved (`bind`) or released (`release`), an event is published on the _vertx
.discovery.usage_ address. This address is configurable from the {@link io.vertx.servicediscovery.ServiceDiscoveryOptions}.

It lets you listen for service usage and map the service bindings.

The received message is a {@link io.vertx.core.json.JsonObject} containing:

* the record in the `record` field
* the type of event in the `type` field. It's either `bind` or `release`
* the id of the service discovery (either its name or the node id) in the `id` field

This `id` is configurable from the {@link io.vertx.servicediscovery.ServiceDiscoveryOptions}. By default it's "localhost" on
single node configuration and the id of the node in clustered mode.

You can disable the service usage support by setting the usage address to `null` with
{@link io.vertx.servicediscovery.ServiceDiscoveryOptions#setUsageAddress(java.lang.String)}.


== Service discovery bridges

Bridges let you import and export services from / to other discovery mechanism such as Docker, Kubernetes, Consul...
Each bridge decides how the services are imported and exported. It does not have to be bi-directional.

You can provide your own bridge by implementing the {@link io.vertx.servicediscovery.spi.ServiceImporter} interface and
register it using
{@link io.vertx.servicediscovery.ServiceDiscovery#registerServiceImporter(ServiceImporter, io.vertx.core.json.JsonObject)}.

The second parameter can provide an optional configuration for the bridge.

When the bridge is registered the {@link io.vertx.servicediscovery.spi.ServiceImporter#start} method is called.
It lets you configure the bridge. When the bridge is configured, ready and has imported / exported the initial services, it must complete the given {@link io.vertx.core.Future}.
If the bridge starts method is blocking, it must use an {@link io.vertx.core.Vertx#executeBlocking(io.vertx.core.Handler, boolean, io.vertx.core.Handler)} construct, and complete the given future object.

When the service discovery is stopped, the bridge is stopped.
The {@link io.vertx.servicediscovery.spi.ServiceImporter#close(io.vertx.core.Handler)} method is called that provides the opportunity to cleanup resources, removed imported / exported services...
This method must complete the given {@link io.vertx.core.Future} to notify the caller of the completion.

Notice than in a cluster, only one member needs to register the bridge as the records are accessible by all members.

== Additional bridges

In addition of the bridges supported by this library, Vert.x Service Discovery provides additional
bridges you can use in your application.

include::consul-bridge.adoc[]

include::kubernetes-bridge.adoc[]

include::zookeeper-bridge.adoc[]

include::docker-links-bridge.adoc[]

== Additional backends

In addition of the backend supported by this library, Vert.x Service Discovery provides additional
backends you can use in your application.

include::redis-backend.adoc[]
