Vert.x Basics

In part 1, we discussed some of the ideas behind Vert.x. In this, the second post in the series, we will discuss some more details and coding conventions used in Vert.x. Vert.x is pretty easy to get started with. The most difficult part is getting used to the asynchronous nature of the code. Let’s begin a little by talking about callbacks, what they look like, and how they are used.


Callbacks

A Callback is defined by Wikipedia as “a piece of executable code that is passed as an argument to other code, which is expected to call back (execute) the argument at some convenient time”. A simple way to think about this is perhaps like a text message you send via your cell phone. You send the message asking your friend to call you and let you know when the pizza arrives. You may get a return call from your friend immediately (the pizza is already there) or some other time later (after the pizza arrives). Callbacks in programming work in a similar fashion. You submit a task to be completed and along with that task you provide a callback Lambda which the underlying system will execute once the requested task is complete, sometimes providing the results of that task to the callback. Let’s see an example:

Callbacks.java
import io.vertx.core.AbstractVerticle;
import io.vertx.core.AsyncResult;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.logging.Logger;
import io.vertx.core.logging.LoggerFactory;

public class Callbacks extends AbstractVerticle {

    private static final Logger LOG = LoggerFactory.getLogger(Callbacks.class);

    public void readFileHandler(AsyncResult<Buffer> res) { (1)
        if (res.succeeded()) {
            Buffer fileContents = res.result();
            // Do something with the file contents
        } else {
            // Handle the error
            LOG.error("Error reading file", res.cause());
        }
    }

    @Override
    public void start() {
        vertx.fileSystem().readFile("/path/to/file.txt", this::readFileHandler); (2)
    }
}
1 The callback function to be passed
2 The functional call which accepts the callback as a parameter

In our example above, we pass the callback as a parameter to the readFile method, and the API is designed such that
when the file has been read completely it will call that method/function with the results of the file read.

Verticles

One of the key components of Vert.x is a Verticle. Verticles in Vert.x are roughly equivalent to Actors that would you see in Erlang or Akka. A simple way to think about actors is that they are individual single-purpose programs which have a specific function and which are communicated with via message passing. This has a distinct advantage: Since actors are only accessible via message passing, there is no shared state, and there are no concurrency issues. Let’s use another analogy.

Tom has gathered a group of contractors to build a house. He could hand a copy of the blueprints to each contractor and tell them to go and start, but there is a good chance that they will get in each other’s way. Instead, Tom breaks down the plans into individual tasks which the contractors specialize in. Jeff is a framer, so when Tom needs frames built a message is passed to Jeff with details about where and what sort of frame to build and Jeff proceeds. Wes is a mason, so Tom sends Wes messages about when and where he needs foundations built and Wes proceeds. Austyn is a roofer, so she gets messages about where and what sorts of roofing get built. Tom acts as a broker, sending messages to each contractor (Actor) to fulfill individual tasks. When those tasks are complete, the Actor will either sit idle and wait for the next message or they will send a message back to Tom to let him know that the task is complete. Sometimes the needs of each contractor have coordination, so it is also possible for individual contractors to send messages to each other in order to coordinate their work.

Verticles work in a simlar fashion. A Verticle SHOULD be built with a single task in mind and it should be communicated with via messages. This gives us the advantage that each of the Actors/Verticles/Contractors can work in parallel without causing problems with other Actors/Verticles/Contractors.

The Event Bus

We have discussed that Actors/Verticles communicate via messages, and the Event Bus is how those messages are passed in Vert.x. The Event Bus provides a standard way for messages to be sent between Verticles inside a single Vert.x application AND between Vert.x applications. In addition, the Vert.x Event Bus can take advantage of the Clustering capabilities inherent in Vert.x to send messages across multiple nodes. The Event Bus is also fairly flexible in that messages can be sent in multiple ways:

  1. Publish - A Message is sent and ALL consumers recieve a copy (throughout a cluster even)
  2. Send - A Message is sent and ONLY ONE consumer recieves a copy (Determined by the Vert.x Event Bus and availability)
  3. Send And Expect Response - The same as send, but the consumer is able to send a response with success/fail and a result.

In addition, message consumers can work in multiple ways:

  1. Consumer - Listens for messages from anywhere in a Cluster
  2. Local Consumer - Only accepts messages for the Vert.x node it operates within

Clustering

In the previous section Clustering was mentioned, and it should be clarified that Clustering is a capability designed in from the beginning in Vert.x. There are a number of Cluster Manager implementations available and we will discuss them in more depth later in this book. For now, realize that Vert.x applications are easily scaled horizontally by using the built-in clustering capabilities which Vert.x provides. And more than just facilitating the Event Bus, the cluster managers are capable of organizing shared data throughout a cluster in a way which is safe for multiple concurrent nodes.

Come back tommorrow, when we will start to write actual Vert.x code, starting with a simple series of HelloWorld examples.

Comments

Popular Posts