This article is the first in a series of articles based on the presentation of the university reactive Applications with Eclipse Vert.x to which I attended the 04/04/2017, first day of the 2017 edition of Devoxx France. The university was presented by Julien Viet (current leader of Vert.x project) and Julien Ponge (Core developer in the Vert.x project).

Vert. x is a project which I heard about during an edition of Devoxx France 3 or 4 years ago, and which I discovered then through a presentation of Devoxx France in 2015, in a tools in action (presentation of 30min). If technically the concepts of the library were clear, I could not, however, summarize what it was in one sentence. My recent interest in the reactive systems approach has led me to take an interest in Vert.x, which claims to be compliant with this approach. From this perspective, Vert.x can be summed up in one sentence: a toolbox for building reactive systems. This implies frameworks of various use, both in the classical field of enterprise applications and in the embedded field, where the tool proposes a framework simplifying the construction of reactive applications. Vert.x also has the specificity of being a polyglot library, currently implemented in Java, Javascript, Groovy, Ruby, Ceylon, Scala and Kotlin.

Vert.x being described as a toolbox for the construction of reactive systems, we will start by showing through an example of Vert.x application type Hello World what it means.

REMINDER ON REACTIVE SYSTEMS AFTER THE MANIFEST

The manifest considers that reactive systems are systems that meet the following properties:

  • Responsive: ability to respond quickly in all circumstances. This implies an ability to quickly detect errors and manage them.
  • Resilience: The ability of the system to remain available in case of errors. Resilience can be achieved through the replication of services, by the bulkheading of the effects of errors and the delegation of responsibilities.
  • Elasticity: the ability of the system to remain available during load changes, through the allocation or deallocation of resources.
  • Message-driven: the asynchronous nature of message-based communication reinforces the partitioning between components and thus promotes decoupling and location transparency.

FIRST VERSION OF HELLO WORLD

1 public class HelloWorld extends AbstractVerticle {
2 
3     @Override
4     public void start() {
5         vertx.createHttpServer().requestHandler(request -> request.response().end("Hello World!")).listen(8080);
6     }

Listing 1-1 HelloWorld web server with Vert.x

Listing 1.1 presents the simplest version of the Hello World application in Vert.x, an HTTP server that responds by returning the message “Hello World! ».

Let us dwell for a moment on this relatively simple code but which involves the use of one of the main elements of Vert.x: the verticles. We will return to the verticles later, for now we must consider the verticles as components of a Vert.x application, subject to life cycles controlled by Vert.x. Our server therefore becomes a verticle simply by inheriting from the AbstractVerticle class of Vert.x.

Is our application reactive?

  • Responsiveness: the application being a monolith, an error is total and gives no chance of response to the customer. Obviously, the example is so simple that one wonders what might not work in this application other than a hardware error. To facilitate reasoning, imagine that the message “Hello World! “ is the result of a call potentially subject to errors, it is often the case in reality.
  • Resilience: Again, the monolithic aspect makes that the system error does not easily give the possibility to contain the error at some point in the system.
  • Elasticity: When changing loads, the number of instances of the entire application must be increased or decreased. This is not optimal, because if it is a particular service that is heavily requested, then it is a shame to have to deploy the entire application just to replicate this service buried in the monolith.
  • Message-driven: the application being a monolith, the components are strongly coupled and thus mutually exposed to their respective errors.

So, in order for our system to be evaluated as reactive or not, we will have to start by going back and splitting it into distributed services. So let’s do this split in the next step.

SECOND VERSION OF HELLO WORLD

As we mentioned the possibility, suppose the message « Hello World! » is provided by a service, and make this service a separate component, otherwise called another verticle, exposing its interface through HTTP. The Web server will therefore contact this service by an HTTP call to retrieve the message, and return it as a response to the received request. So let’s call the new service GreetingService.

For the sake of clarity, we will present the code of the new service, but it is the evolution of the code of the initial server which must hold our attention.

1 public class GreetingService extends AbstractVerticle {
2 
3     @Override
4     public void start() {
5 
6         vertx.createHttpServer().requestHandler(
7                 request -> request.response().end(new JsonObject().put("message", "Hello World!").encode())).listen(8081, "localhost");
8     }
9 }

Listing 1-2 New GreetingService

Let’s see HelloWorld’ evolution

public class HelloWorld extends AbstractVerticle {
 2 
 3     @Override
 4     public void start() {
 5         WebClient client = WebClient.create(vertx);
 6         HttpRequest<JsonObject> httpRequest = client.get(8081, "localhost", "/").as(BodyCodec.jsonObject());
 7         vertx.createHttpServer().requestHandler(request -> {
 8             httpRequest.send(ar -> {
 9                 if (ar.succeeded()) {
10                     String message = ar.result().body().getString("message");
11                     request.response().end(message);
12                 } else {
13                     request.response().setStatusCode(500).end();
14                 }
15             });
16         }).listen(8080, "localhost");
17     }
18 }

Listing 1-3 Hello World Using GreetingService

Let’s evaluate the properties of the new version of the application:

  • Availability : We note an improvement in this direction, because now in the event of an error in the GreetingService call, explicit processing is done to return the status to the client (line 13). This error management remains improvable however . However, we are not spared by the so called timeout problems for example, which have a similar impact on the user.
  • Resilience: In the event of an unrecoverable error in the GreetingService, we unfortunately have no way of reestablishing a normal service for the user who is condemned to receive the fallback response. So resilience is not really achieved.
  • Elasticity: because of the explicit reference of the GreetingService address (machine plus port number), the replication of the service would not benefit the HelloWorld server, in any case not without having to go through external tools that allow to replace the references explicit by logical names in distributed systems. But as we will see in the 3rd and last version of our application, one of the main strengths of Vert.x is to achieve resilience by directly using the native features of the library.
  • Message oriented : the communication between the two components is certainly asynchronous, but the client has an explicit reference to the server.

We will therefore proceed to a final evolution always in order to make the application reactive.

THIRD AND LATEST VERSION OF HELLO WORLD

The change in this version will consist in using one of the main features of Vert.x: the event bus. The event bus, as its name implies, is a messaging bus that allows message-oriented communication with the patterns we know: publish-subscribe, point-to-point with response capability. The event bus will mainly bring us the property of location transparency, and this will have the consequences that we will soon evaluate. For now, here are the codes for the new versions of the two components.

 1 public class GreetingService extends AbstractVerticle {
 2 
 3     @Override
 4     public void start() {
 5         vertx.eventBus().consumer("GreetingService", message -> {
 6             JsonObject reply = new JsonObject().put("message", "Hello World!");
 7             message.reply(reply);
 8         });
 9     }
10 }

Listing 1-4 GreetingService with the event bus

1 public class HelloWorld extends AbstractVerticle {
 2 
 3     @Override
 4     public void start() {
 5         vertx.createHttpServer().requestHandler(request -> {
 6             vertx.eventBus().<JsonObject>send("GreetingService", "", reply -> {
 7                 if (reply.succeeded()) {
 8                     String message = reply.result().body().getString("message");
 9                     request.response().end(message);
10                 } else {
11                     request.response().setStatusCode(500).end();
12                 }
13             });
14         }).listen(8080, "localhost");
15     }
16 }

Listing 1-5 HelloWorld with the event bus

To send or consume messages on the event bus, simply specify the virtual address to which to send or receive the message, and there lies a fundamental difference from the basic HTTP communication that requires the indication of a physical address. In our example, the (arbitrary) name of the address used is GreetingService by GreetingService and HelloWorld, to send messages or reply to received messages.

Now let us evaluate the degree of compliance of this version of the application with the properties of the reactive systems.

  • Responsiveness: The introduction of the event bus did not directly improve the availability of the application.
  • Resilience: thanks to the virtual address used by the communication through the event bus, the location transparency of localization is achieved between the two components, and consequently, in case of a non-recoverable error of the GreetingService, the HelloWorld server message can be forwarded to another instance of the service, already existing or created on the occasion, to continue to provide a normal service to the user. So resilience is achieved.
  • Elasticity: As with resilience, the location transparency makes the application elastic. In case of strong solicitation, the GreetingService can be replicated, and Vert.x will dynamically balance the calls to the different replications. This becomes possible by the use of the virtual address used in the communication through the event bus.
  • Message-oriented: thanks to asynchronous communication and virtual addressing, we achieve the desired level of isolation between components.

This example of application has allowed us to see through its evolutions and see why Vert.x is considered reactive. This is because it provides the functionality required to naturally build applications that respond to the properties of reactive systems.

We have just seen that thanks to its features Vert.x allows the construction of reactive systems.

To understand the basic principles behind Vert.x, five key topics will be covered in a series of 5 articles « Vert.x Basics »:

  • x Basics (1/5): The concurrency model
  • x Basics (2/5): Concurrency and scalability with verticles
  • x Basics (3/5): High availability and failover
  • x Basics (4/5): Asynchronous event management
  • x Basics (5/5): The event bus