aakashdp
aakashdp

Reputation: 143

Why is Vert.x executing code synchronously?

Need help with understanding the code execution flow. On calling the sayHi() method below, the onSuccess handler is executed first and then the return statement gets executed. I had the understanding that the function will return immediately and the onSuccess handler will get executed after that.

public String sayHi() {
    sayHello().onSuccess(s  -> {
      System.out.println(s);
    });
    return "hi";
  }

  public Future<String> sayHello() {
    String s1 = "hello";
    return Future.succeededFuture(s1);
  }

EDIT: I'm trying to draw a comparison it with JavaScript Promises, where the function passed to the then method always gets executed after the rest of the statements are executed. Like calling the test method below will print 'hi','bye' and then 'Success'

    var promise2 = new Promise((resolve, reject) => {
        resolve("Success!")
    });
      
   function test() {
      console.log("hi");
      promise2.then((value) => {
        console.log(value);
      });
      console.log("bye");
  }

Upvotes: 2

Views: 373

Answers (2)

O.Badr
O.Badr

Reputation: 3121

From the documentation:

You cannot interact directly with the result of a future, instead you need to set a handler that will be called when the future completes and the result is available, like any other kind of event.

So the Future result is available immediately and there is no I/O task to wait for: like an HTTP response, or reading from file system...etc.

All your code is running in a single thread you can verify it yourself:

public String sayHi() {
    sayHello().onSuccess(s  -> {
      System.out.println("Thread name ==> " + Thread.currentThread().getName()); // e.g: Thread name ==> main
      System.out.println(s);
    });
    return "hi";
  }

  public Future<String> sayHello() {
    System.out.println("Thread name ==> " + Thread.currentThread().getName()); // e.g: Thread name ==> main
    String s1 = "hello";
    return Future.succeededFuture(s1);
  }

But the code below may run in different order (we are doing I/O task here):

  public String sayHi() {
    sayHello().onSuccess(s  -> {
      System.out.println(s);
    });
    return "hi";
  }

  public Future<String> sayHello() {
    var vertx = Vertx.vertx();
    var fs = vertx.fileSystem();
    return fs.props( ".").map(fileProps -> "In getHelloFuture() method");  // I/O task
  }

Upvotes: 0

Thomas Kl&#228;ger
Thomas Kl&#228;ger

Reputation: 21435

The problem is that Future.succeededFuture(s1) returns an already completed Future that is not associated with an ExecutionContext.

Since it is already completed and not associated with an ExecutionContext it executes the onSuccess() handler synchronously.

You need to tell vert.x to create the Future<String> for you on a separate thread. You can try

import io.vertx.core.Future;
import io.vertx.core.Vertx;

public class Async {
    private static Vertx vertx;

    public static void main(String[] args) {
        vertx = Vertx.vertx();
        System.out.println(sayHi());
        vertx.close();
    }
    public static String sayHi() {
        sayHello().onSuccess(s  -> {
            System.out.println(s);
        });
        return "hi";
    }

    public static Future<String> sayHello() {
        return vertx.executeBlocking(p -> {
            String s1 = "hello";
            p.complete(s1);
        });
    }
}

Note: I don't have much experience with vert.x, so there could be better approaches.

Upvotes: 1

Related Questions