Future Composition in Vert.x
Tags: vertx, async, java
Published: 2020-05-20 11:42:45

For those who don't know, Vert.x is an event driven and non blocking application toolkit.
It's polyglot, so you can use it with different languages (as **Java**, **Kotlin**, **JavaScript**, **Groovy**, **Ruby** or **Scala**).

### What does "non blocking" mean?
In synchronous programming, when a function is called, the caller has to wait until the result is returned. 
This behaviour could lead to performance issues.

Often the "obvious solution" seems to be [concurrent programming](https://en.wikipedia.org/wiki/Concurrent_computing), but dealing with shared resources and threads is not easy and deadlocks are around the corner.

Explaining how Vert.x guarantees asynchrony through the **event loop** concept is not in the scope of this article, but anything you may want to know gets unraveled in the great [Gentle guide to async programming with Vert.x](https://vertx.io/docs/guide-for-java-devs/).

In a "non blocking" world, when the result of a function can be provided immediately, it will be. Otherwise a handler is provided to handle it when it will be ready.
```java 
asyncFunctionCall(result -> {
    doSometingWith(result);
})
```
Usualy a big "but" gets raised the first time an async piece of code is seen: *But... I need that result now!*

This kind of programming requires a mindset change: it's necessary to know and understand the main patterns.

### Futures vs Callbacks
There are two ways to deal with async calls in Vert.x.

* Pass a callback that will be executed on call completion.
* Handle a future returned from the function/method call.

#### Callback
```java
asyncComputation(asyncResult -> {
  if (asyncResult.succeeded()) {
    asyncResult.result()
    // do stuff with result
  } else {
    // handle failure
  }
})
```

A callback is a function passed to an async method used to handle the result of its computation.
It's simple to implement but it brings some drawbacks:
* Unit testing becomes not-so-immediate
* Leads to the dreaded [Callback Hell](http://callbackhell.com/)
* There's more code to be written.

#### Future
```java
Future future = asyncComputation()

future.onSuccess(result -> {
  // do stuff
})

future.onFailure(cause -> {
  // handle failure
})
```

To avoid the problems listed for the "callback way", Vert.x implements a concept called **Future**.

A future is an object that **represents the result of an action that may, or may not, have occurred yet** (cf. [apidoc](https://vertx.io/docs/apidocs/io/vertx/core/Future.html)).

##### How to switch from a callback-like call to a future one
Consider the callback example shown above. 
We want a Future object to take advantage of the patterns described below, but `asyncComputation` is a function from another library, so we cannot modify it.

We can use a **Promise**.
According to the [apidoc](https://vertx.io/docs/apidocs/io/vertx/core/Promise.html), it **represents the writable side of an action that may, or may not, have occurred yet.**
It perfectly fits our needs:

```java
Promise promise = Promise.promise();
asyncComputation(asyncResult -> {
  if (asyncResult.succeeded()) {
    promise.complete(asyncResult.result());
  } else {
    promise.fail(asyncResult.cause());
  }
})
return promise.future()
```

That's it. We transformed a callback into a future.
The Promise API's give us a way to make this code more readable:
```java
Promise promise = Promise.promise();
asyncComputation(promise::handle)
return promise.future()
```

The *handle* method takes care of the completion or failure of the promise, given an async result.

### Future patterns
The Future object implements some interesting patterns that smartly help resolving async issues:
* Map
* Compose
* Recover

#### Future Mapping
For those of you who know about the `map` function, part of the java `Stream` API, this feature should be immediate to understand.

The Future's map function accepts a function that transforms the result from one type to another.
```java
asyncComputation() // returns a Future<String>
  .map(Integer::valueOf) // returns a Future<Integer>
  .onSuccess(...)
  .onFailure(...)
```

#### Future Composition
The `compose` method is similar to `map`, but is used when the mapping is an async operation itself:
```java
asyncComputation()
  .map(Integer::valueOf)
  .compose(id -> retrieveDataById(id)) // retrieveDataById returns a Future
  .onSuccess(...)
  .onFailure(...)
```

#### Future Recovery
Futures can succeed, but can also fail. 
To handle a failed future and consider a different behaviour, `recover` function can be used:
```java
asyncComputation()
  .map(Integer::valueOf)
  .recover(cause -> Future.succeededFuture(0)) // when Integer::valueOf fails, the future could be recovered with a default value
  .compose(id -> retrieveDataById(id))
  .onSuccess(...)
  .onFailure(...)
```

#### Concurrent composition
To handle multiple future results at the same time, `CompositeFuture` is the class needed, it provides two static factory methods:

`all` returns a future that succeeds if all the futures passed as parameters succeed, and fails if at least one fails.
```java
CompositeFuture.all(futureOne, futureTwo)
  .onSuccess(compositeResult ->
    // all futures succeeded
  )
  .onFailure(cause -> 
    // at least one failed
  );
```

`any` returns a future that succeeds if any one of the futures passed as parameters succeed, and fails if all fail.
```java
CompositeFuture.any(futureOne, futureTwo)
  .onSuccess(compositeResult ->
    // at least one succeed
  )
  .onFailure(cause -> 
    // all failed
  );
```

### Conclusions
Future composition API in Vert.x represents a solid way to write simple and affordable async code.
Always remember:
* never throw exceptions into async code, use failed future instead to handle failure behaviours.
* at the end of a future composition, don't forget to handle future's successes (`onSuccess`) and failures (`onFailure`)