Vert.x pitfalls in reactive system programming

Introduction

You probably know that Vert.x is a reactive system based on an event loop. It allows for high scale, high availability and clustering. You may think, why not use it for my next scale project. But if you are not used to asynchronous programming in reactive systems you may find yourself dealing with unexpected situations which you didn’t anticipate. For example look at the following code snippet. What is the exception order here:

readFile();
processFile();

Since we do not use threads a programmer who looks at the code would say that readFile() would run until it completes and thereafter processFile() would run. In Vert.x that would not necessarily happen. Why? readFile() probably contains blocking code and processFile() may start before readFile() has completed.

Reactive system

Vert.x is reactive event driven system utilizing an event loop to process events. The event loop mustn’t be blocked otherwise it will block the entire application. To avoid this type of blocking Vert.x uses handlers for executing blocking code.

e.g.

someObject.blockingCodeMethod(handler -> {
	//After completion code comes here
}

Let’s go back to the example of readFile() and processFile(). The method processFile() depends on method readFile() and should only run after readFile() has completed. This means we will need to implement this in our code.

Let’s look at the example below:

public class ReadFileVerticle1 extends AbstractVerticle {

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

    @Override
    public void start() throws Exception {
        super.start();
        readFile();
        processFile();
    }

    private void readFile() {
        vertx.fileSystem().readFile("/Users/yaniv/system.log", fileHandler ->{
           if(fileHandler.succeeded()) {
               System.out.println("Finished reading file");
           } else {
               System.out.println("Failed to read file");
           }
        });
    }

    private void processFile() {
        System.out.println("Process file");
    }
}

Executing the example will print the following:

Process file
Finished reading file

The problem here as you can see is that we start processing the file before we finished reading it.

The following code handles this problem

public class ReadFilehVerticle2 extends AbstractVerticle {

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

    @Override
    public void start() throws Exception {
        super.start();
        readFile(handler -> {
            processFile();
        });
    }

    private void readFile(Handler<AsyncResult<Void>> handler) {
        vertx.fileSystem().readFile("/Users/yaniv/system.log", fileHandler -> {
            if (fileHandler.succeeded()) {
                System.out.println("Finished reading file");
                handler.handle(Future.succeededFuture());
            } else {
                handler.handle(Future.failedFuture(fileHandler.cause()));
                System.out.println("Failed to read file");
            }
        });
    }

    private void processFile() {
        System.out.println("Process file");
    }
}

The print-out this time will be:

Finished reading file
Process file

Summary

We saw that things can be tricky in Vert.x and code may not be execute like in synchronized systems.

Senior Java Developer

Backend Group
Thank you for your interest!

We will contact you as soon as possible.

Send us a message

Oops, something went wrong
Please try again or contact us by email at info@tikalk.com