nimo23
nimo23

Reputation: 5680

compose with vertx for sequential code

I have two operations step_1() and step_2() and want to execute step_2() AFTER step_1().

With normal java this would be:

step_1();
step_2();

With vertx I have to use vertx-compose(). Am I right?

According to https://groups.google.com/forum/#!topic/vertx/FuvlPLpoGOA, I dont need Futures for sequential code.

"If you want to do each request sequencially you dont need futures."

So how can I do that without using futures?

I dont know, if this matters: My Vertx from which this code is executed is a "Worker"-Verticle.

@Override
public void start(Future<Void> fut) throws IOException {

Future<Void> step_1 = Future.future();
    step_1.compose(res -> {
        // If the future succeeded
        Future<Void> step_2 = step_1();

        step_2.compose(res2 -> {
            step_2();

        }, Future.future().setHandler(handler -> {
            // If the future failed
        }));

        //I dont need that
    }, Future.future().setHandler(handler -> {
        // If the future failed
    }));

}

public void step_1(){
..
}

public void step_2(){
..
}

Is this the right and shortest (!) way?

Upvotes: 4

Views: 14667

Answers (4)

berserkk
berserkk

Reputation: 1007

"If you want to do each request sequencially you dont need futures."

No, it's not. In asynchronous frameworks like Vert.x, input/output operations are non-blocking. It means, that if you call few asynchronous operations, they'll start working simultaneously. And if you want to do few requests sequentially, then you should use futures or callbacks to execute new request only after previous one finished successfully.

Check this code with futures, newer version with RxJava 2 and article about project.

@Override
public Future<Optional<Todo>> getCertain(String todoID) {
    Future<Optional<Todo>> result = Future.future();
    redis.hget(Constants.REDIS_TODO_KEY, todoID, res -> {
        if (res.succeeded()) {
            result.complete(Optional.ofNullable(
                res.result() == null ? null : new Todo(res.result())));
        } else
            result.fail(res.cause());
    });
    return result;
}

@Override
public Future<Todo> update(String todoId, Todo newTodo) {
    return this.getCertain(todoId).compose(old -> {
        if (old.isPresent()) {
            Todo fnTodo = old.get().merge(newTodo);
            return this.insert(fnTodo)
                .map(r -> r ? fnTodo : null);
        } else {
            return Future.succeededFuture();
        }
    });
}

Upvotes: 2

y ramesh rao
y ramesh rao

Reputation: 3004

Below is an example of chaining of Future, I have made the example very trivial nonetheless it showcases the concept.

@RunWith(VertxUnitRunner.class)
public class Chaining {
    private Vertx vertx = Vertx.vertx();

    @Test
    public void futures_chaining(TestContext context) throws Exception {
        Async async = context.async();

        firstOperation()
                .compose((outcome) -> {
                    System.out.println(outcome);

                    return secondOperation();
                })
                .compose(outcome -> {
                    System.out.println(outcome);

                    /*
                      For stopping unit test we are returning this future                                                                                                                                                              
                      for production use-case this would be Future.succeededFuture 
                      or Future.failedFuture depending on your method outcomes
                     */
                    return Future.future(handle -> async.complete());
                });
    }

    private Future<String> firstOperation() {
        Future<String> future = Future.future();

        vertx.setTimer(1000, delay -> future.complete("First Operation Complete"));

        return future;
    }

    private Future<String> secondOperation() {
        Future<String> future = Future.future();

        vertx.setTimer(1000, delay -> future.complete("Second Operation Complete"));

        return future;
    }
}

Upvotes: 6

Dave Taubler
Dave Taubler

Reputation: 1091

RxJava exists specifically to compose async events: http://vertx.io/docs/vertx-rx/java/

Assuming both step_1() and step_1() aren't designed to return results (i.e. they effectively return void) then you could change them to return Observable or Single and chain them together similar to this:

step_1().doOnSuccess(this::step_2()).subscribe(/* control resumes here */);

RxJava (or rather, reactive programming in general) takes a little bit to wrap your head around it, but I would strongly recommend using it if you're planning to chain together async operations.

Upvotes: 2

Niraj Chauhan
Niraj Chauhan

Reputation: 7880

Pass step_2 as argument to step_1

@Override
public void start(Future<Void> fut) throws IOException {
    step_1(step_2);
}

private void step_1(Runnable function){
    someAsynccall("some-arg", response -> {
        function.run();
    }).end();
}

private void step_2(){
    // do something
}

Upvotes: 0

Related Questions