'How to return an async result from a sync method in vertx?

I am using executeBlocking from vertx in a for loop to parallelise the processing of a result, and collating the results using a CompositeFuture. Based on all the results, I want to return some value from the method, but lambda function inside CompositeFuture's handler is not letting me do so. How to work with this usecase?

Code for reference:

public Response call() throws Exception {
    List<Future> futureList = new ArrayList<>();
    //services is a global variable, an arraylist of services
    for(String service: services) {
        Future serviceFuture = Future.future();
        futureList.add(serviceFuture);

        vertx.executeBlocking(implementTask(service, serviceFuture), false, asyncResult -> {
            if (asyncResult.failed()) {
                LOGGER.error("Task FAILED for service {}", service, asyncResult.cause());
            }
        });
    }

    CompositeFuture.all(futureList).setHandler(asyncResult -> {
        if(asyncResult.succeeded()) {
            LOGGER.debug("Task completed successfully");
            return new Response(ResponseStatus.SUCCESS);
        } else {
            LOGGER.error("Task FAILED", asyncResult.cause());
            return new Response(ResponseStatus.FAILED);
        }
    });
}


Solution 1:[1]

You can't do this. Your call() method should return Future<Result> and not the Result. Then you would need to attach the callback handler on your original caller. This is the way that async methods propagate the result in Vert.x.

public Future<Response> call() throws Exception {
    Promise<Response> promise = Promise.promise();
    List<Future> futureList = new ArrayList<>();
    //services is a global variable, an arraylist of services
    for(String service: services) {
        Future serviceFuture = Future.future();
        futureList.add(serviceFuture);

        vertx.executeBlocking(implementTask(service, serviceFuture), false, asyncResult -> {
            if (asyncResult.failed()) {
                LOGGER.error("Task FAILED for service {}", service, asyncResult.cause());
            }
        });
    }

    CompositeFuture.all(futureList).setHandler(asyncResult -> {
        if(asyncResult.succeeded()) {
            LOGGER.debug("Task completed successfully");
            promise.complete(new Response(ResponseStatus.SUCCESS));
        } else {
            LOGGER.error("Task FAILED", asyncResult.cause());
            promise.fail("Failed");
        }
    });
    return promise.future();
}

Then the call would look like this:

object.call().onSuccess(resultHandler - > {
    //Code when call succeeded
}).onFailure(failureHandler - > {
    //Code when call failed
});

Note: This example is using Vert.x 4. If you are using a version of Vert.x less than 4, then the syntax is a bit different, but the point stays the same.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 user3520975