https://github.com/cescoffier/vertx-completable-future
An implementation of CompletableFuture for Vert.x
https://github.com/cescoffier/vertx-completable-future
Last synced: about 1 year ago
JSON representation
An implementation of CompletableFuture for Vert.x
- Host: GitHub
- URL: https://github.com/cescoffier/vertx-completable-future
- Owner: cescoffier
- License: apache-2.0
- Created: 2016-08-09T15:08:17.000Z (over 9 years ago)
- Default Branch: master
- Last Pushed: 2023-04-02T15:23:50.000Z (almost 3 years ago)
- Last Synced: 2025-02-27T06:02:28.171Z (about 1 year ago)
- Language: Java
- Size: 102 KB
- Stars: 80
- Watchers: 8
- Forks: 29
- Open Issues: 7
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome-java - Vert.x Completable Future
README
# Vert.x Completable Future
This project provides a way to use the Completable Future API with Vert.x.
## Why can't you use Completable Future with Vert.x
Using Completable Future with Vert.x may lead to some thread issues.
When you execute an asynchronous operation with Vert.x, the `Handler>` is called on on the same thread as the method having enqueued the asynchronous operation. Thanks to this _single-threaded_ aspect, Vert.x removes the need of synchronization and also it improves performances.
Completable Future uses a fork-join thread pool. So callbacks (dependent stages) are called in a thread of this pool, so it's not the caller thread.
This project provides the Completable Future API but enforces the Vert.x threading model:
* When using `xAsync` methods (without `executor`), the callbacks are called on the Vert.x context
* When using non-async, it uses the caller thread. If it's a Vert.x thread the same thread is used. If not called from a Vert.x thread,
it still uses the caller thread
* When using `xAsync` methods with an `Executor` parameter, this executor is used to execute the callback (does not enforce the Vert.x thread system)
## Examples
All methods taking a `Vertx` instance as parameter exists with a `Context` parameter.
### Creating a VertxCompletableFuture
```
// From a Vert.x instance
CompletableFuture future = new VertxCompletableFuture(vertx);
// From a specific context
Context context = ...
CompletableFuture future = new VertxCompletableFuture(context);
// From a completable future
CompletableFuture cf = ...
CompletableFuture future = VertxCompletableFuture.from(context, cf);
// From a Vert.x future
Future fut = ...
CompletableFuture future = VertxCompletableFuture.from(context, fut);
```
You can also pass a `Supplier` or a `Runnable`:
```
// Run in context
CompletableFuture future = VertxCompletableFuture.supplyAsync(vertx, () -> return "foo";);
// Run in Vert.x worker thread
CompletableFuture future = VertxCompletableFuture.supplyBlockingAsync(vertx, () -> return "foo");
CompletableFuture future = VertxCompletableFuture.runAsync(vertx, () -> System.out.println(foo"));
CompletableFuture future = VertxCompletableFuture.runBlockingAsync(vertx, () -> System.out.println(foo"));
```
_*BlockingAsync_ method uses a Vert.x worker thread and do not block the Vert.x Event Loop.
### Stages
Once you have the `VertxCompletableFuture` instance, you can use the `CompletableFuture` API:
```
VertxCompletableFuture future = new VertxCompletableFuture<>(vertx);
future
.thenApply(this::square)
.thenAccept(System.out::print)
.thenRun(System.out::println);
// Somewhere in your code, later...
future.complete(42);
```
You can compose, combine, join completable futures with:
* combine
* runAfterEither
* acceptEither
* runAfterBoth
* ...
### All and Any operations
The `VertxCompletableFuture` class offers two composition operators:
* `allOf` - execute all the passed `CompletableFuture` (not necessarily `VertxCompletableFuture`) and calls dependant stages when all of the futures have been completed or one has failed
* `anyOf` - execute all the passed `CompletableFuture` (not necessarily `VertxCompletableFuture`) and calls dependant stages when one of them has been completed
Unlike `CompletableFuture`, the dependent stages are called in the Vert.x context.
```
HttpClientOptions options = new HttpClientOptions().setDefaultPort(8080).setDefaultHost("localhost");
HttpClient client1 = vertx.createHttpClient(options);
HttpClient client2 = vertx.createHttpClient(options);
VertxCompletableFuture requestA = new VertxCompletableFuture<>(vertx);
client1.get("/A").handler(resp -> {
resp.exceptionHandler(requestA::completeExceptionally)
.bodyHandler(buffer -> {
requestA.complete(Integer.parseInt(buffer.toString()));
});
}).exceptionHandler(requestA::completeExceptionally).end();
VertxCompletableFuture requestB = new VertxCompletableFuture<>(vertx);
client2.get("/B").handler(resp -> {
resp.exceptionHandler(requestB::completeExceptionally)
.bodyHandler(buffer -> {
requestB.complete(Integer.parseInt(buffer.toString()));
});
}).exceptionHandler(requestB::completeExceptionally).end();
VertxCompletableFuture.allOf(requestA, requestB).thenApply(v -> requestA.join() + requestB.join())
.thenAccept(i -> {
tc.assertEquals(65, i);
async.complete();
});
}
```
### From / To Vert.x Futures
You can transform a `VertxCompletableFuture` to a Vert.x `Future` with the `toFuture` method.
You can also creates a new `VertxCompletableFuture` from a Vert.x `Future` using:
```
Future vertxFuture = ...
VertxCompletableFuture vcf = VertxCompletableFuture.from(vertx, vertxFuture);
vcf.thenAccept(i -> {...}).whenComplete((res, err) -> {...})
```