ARTICLE

Verticles: the basic processing units of Vert.x

From Vert.x in Action by Julien Ponge

This article talks about what verticles are and delves a bit into how they work and how to write them.

_________________________________________________________________

Take 37% off Vert.x in Action. Just enter fccponge into the discount code box at checkout at manning.com.
_________________________________________________________________

Relevant source code for this article can be found here: https://github.com/jponge/vertx-in-action/tree/master/chapter2

A verticle is the fundamental processing unit in Vert.x. The role of a verticle is to encapsulate a technical functional unit for processing events such as exposing an HTTP API and responding to requests, providing a repository interface on top of a database, or issuing requests to a third-party system. Much like components in other technologies such as Enterprise Java Beans, verticles can be deployed and they have a life-cycle.

Readers familiar with the actor concurrency model will find similarities between Vert.x verticles and actors. Actors are a model where autonomous entities (the actors) exclusively communicate with other entities by sending and responding to messages. The similarities between Vert.x verticles and actors isn’t fortuitous coincidence: verticles have a private state that may be updated when receiving events, they can deploy other verticles, and they can communicate via message-passing. Verticles don’t necessarily follow the orthodox modern definition of actors, but it’s fair to consider Vert.x at least as being inspired by actors.

Let’s now dive into writing verticles.

Writing a verticle

Because verticles are a key concept in Vert.x, we’ll look into how they work. Before that, let’s write a small verticle that processes two types of events: periodic timers and HTTP requests.

Preparing the project

We’ll use a common project for all samples in this article, using the Gradle project descriptor of listing 1.

Listing 1. Gradle for the samples

plugins {
java
}

repositories {
mavenCentral()
}

dependencies {
implementation("io.vertx:vertx-core:3.8.0") ❶

implementation("ch.qos.logback:logback-classic:1.2.3") ❷
}

tasks.create<JavaExec>("run") { ❸

main = project.properties.getOrDefault("mainClass", "chapter2.hello.HelloVerticle") as String
classpath = sourceSets["main"].runtimeClasspath
systemProperties["vertx.logger-delegate-factory-class-name"] = "io.vertx.core.logging.SLF4JLogDelegateFactory" ❹

}

java {
sourceCompatibility = JavaVersion.VERSION_1_8
}

❶ This is the Vert.x core library dependency.

❷ The dependency provides the logger API and the implementation.

❸ This allows running samples with Gradle from the command line.

❹ This ensures that Vert.x itself also uses logging.

The Gradle build is a simple one for a Java project. Because we have several examples to run, we don’t rely on the Gradle plugin but define our own custom task where we can pass the name of the class to execute. We also take advantage of it to ensure that logging is properly configured and unified to SLF4J.

Listing 2. Logback configuration to reduce Netty verbosity

<configuration>

<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%level [%thread] %logger{0} - %msg%n</pattern> ❷
</encoder>
</appender>

<logger name="io.netty" level="warn"/> ❸

<root level="debug">
<appender-ref ref="STDOUT"/>
</root>
</configuration>

❶ This defines an appender to send events to the console.

❷ The pattern defines how the log events look like.

❸ We drop Netty log events which are more verbose than warnings.

Vert.x uses Netty and logging in Netty is quite verbose with the default Logback configuration. We can reduce the amount of log entries by creating a file and adding the configuration as in listing 2. To make the log samples shorter in this article we also removed event dates and shortened logger class names (). Please refer to the Logback documentation to understand how to configure it [LogbackDoc].

The verticle class

The whole verticle and application fits in the Java class of listing 3.

Listing 3. A sample verticle

package chapter2.hello;

import io.vertx.core.AbstractVerticle;
import io.vertx.core.Vertx;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class HelloVerticle extends AbstractVerticle {
private final Logger logger = LoggerFactory.getLogger(HelloVerticle.class);
private long counter = 1;

@Override
public void start() {
vertx.setPeriodic(5000, id -> { ❶
logger.info("tick");
});

vertx.createHttpServer()
.requestHandler(req -> { ❷
logger.info("Request #{} from {}", counter++, req.remoteAddress().host());
req.response().end("Hello!");
})
.listen(8080);
logger.info("Open http://localhost:8080/");
}

public static void main(String[] args) {
Vertx vertx = Vertx.vertx(); ❸
vertx.deployVerticle(new HelloVerticle()); ❹
}
}

❶ This defines a periodic task every five seconds.

❷ The HTTP server calls this handler on every request.

❸ We need a global Vert.x instance.

❹ This is the simplest way to deploy a verticle.

This verticle defines two event handlers: one for periodic tasks every five seconds, and one for processing HTTP requests in a HTTP server. The method instantiates a global Vert.x instance, and deploys an instance of the verticle.

Defining a verticle code in Java is typically done by specializing the class. There exists a interface that one could in theory implement, but provides all the event processing, configuration and execution plumbing that Vert.x users need.

Because Vert.x is a library and not a framework, you can create a Vert.x instance from a method, or from any other class and then deploy verticles.

The life-cycle of a verticle is made of start and stop events. The class provides and methods that can be overridden. By default, these methods do nothing.

  1. The method typically contains setup and handlers’ initialization, like setting a periodic task handler and starting a HTTP server in listing 3.
  2. The method is implemented when housekeeping tasks are required, such as closing open database connections.

Running and first observations

The application can be launched as a regular Java application by running the method either from an integrated development environment or from the command-line. To run on the command line using Gradle, you can use the following command:

gradle run -PmainClass=chapter2.hello.HelloVerticle

In some of the remaining samples we shortened class definitions. We removed package definitions, imports, and methods which are similar to that of listing 3. When in doubt, please consult the full source code of the samples.

Once the application runs, we can perform a few HTTP requests at http://localhost:8080/ with a web browser or by using command-line tools such as and . The logs shall be similar to that of listing 4.

Listing 4. Sample log output when running

INFO [vert.x-eventloop-thread-0] HelloVerticle - Open http://localhost:8080/
INFO [vert.x-eventloop-thread-0] HelloVerticle – tick ❷
INFO [vert.x-eventloop-thread-0] HelloVerticle - Request #1 from 0:0:0:0:0:0:0:1 ❸
INFO [vert.x-eventloop-thread-0] HelloVerticle - Request #2 from 0:0:0:0:0:0:0:1
INFO [vert.x-eventloop-thread-0] HelloVerticle - Request #3 from 0:0:0:0:0:0:0:1
INFO [vert.x-eventloop-thread-0] HelloVerticle - Request #4 from 0:0:0:0:0:0:0:1
INFO [vert.x-eventloop-thread-0] HelloVerticle – tick

❶ The HTTP server is now ready.

❷ A periodic task event log.

❸ A HTTP request event log.

The Logback configuration that we use shows the name of the thread associated with an event. We can already check an important property of Vert.x verticles in log entries: event processing happens on a single event-loop thread. Both the periodic tasks and HTTP requests processing happen on a thread that appears as in the logs.

An obvious benefit with this design is that a verticle instance is always executing event processing on the same thread, and there’s no need for using thread synchronization primitives. In a multi-threaded design updating the field requires either a block or the usage of . No such issues here and a plain field can be safely used.

Preparation methods such as or may be called from a non-Vert.x thread. This may happen when directly using a object without a verticle, or when writing unit tests. This isn’t a problem as usage of the class methods is thread-safe.

Figure 1. Execution of listing 3

Figure 1 shows the (simplified) interactions between the verticle, the handlers, Vert.x and the event sources. Each arrow represents a method call between the participants. For instance, creates a periodic task handler by calling on the object, which in turns creates a periodic task using a Vert.x-internal timer. In turn, the timer periodically calls back the handler in .

Note that we represented the calls to and as being to the object as a shortcut, but in reality they’re on an object that implements the interface. The class is internal to Vert.x, and because it doesn’t serve the diagram to add another participant we merged it into .

That’s all for this article.

If you want to learn more about the book, check it out on our browser-based liveBook reader here and see this slide deck.

Follow Manning Publications on Medium for free content and exclusive discounts.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store