Skip to content

Promises.any

Richard Hightower edited this page Sep 9, 2016 · 11 revisions

We have any support to Promises. You can create a Promise from other promises. If any of the child promises async return, then the parent promise async returns.

Promise.any(promises...) method returns a promise that resolves as soon as one of promises resolves. It will ignore errors from any of the other promises as long as they don’t all error. It is similar but different than Promises.race from JavaScript. Many JavaScript libs have an any equiv. to Promises.any. Promise.race does not seem as useful as Promise.any, but we might add Promise.race as well.

We also have all support.

Both the reactor and the static class has Promises.all and Promises.any.

any and all example using reactor

// Send to the queue and two tables in Cassandra at the same time, 
// wait until one of them succeed and then resolve the original call. 
reactor.any(Duration.ofSeconds(30),
        messageQueue.sendToQueue(todo)
                .catchError(error -> logger.error("Send to queue failed", error))
                .thenSafe(enqueued -> logger.info("Sent to queue")),
        //Call to save Todo in two table, don't respond until both calls come back.
        reactor.all(Duration.ofSeconds(15),
                futureToPromise( // First call to cassandra.
                        session.executeAsync(insertInto("Todo")...)
                ).catchError(error -> recordCassandraError("add.todo", error))
                        .thenSafe(resultSet -> handleResultFromAdd(...)),
                futureToPromise( // Second call to cassandra.
                        session.executeAsync(insertInto("TodoLookup")...)
                ).catchError(error -> recordCassandraError("add.lookup", error))
                        .thenSafe(resultSet -> handleResultFromAdd(...)))//end all
).catchError(returnPromise::reject)
        .then(v -> returnPromise.resolve(true)).invoke();

Example using Promises.any.

        /** Employe service. */
        EmployeeService employeeService = ...

        /* Promises that expects an employee. */
        Promise<Employee> promise1 = Promises.promise();
        Promise<Employee> promise2 = Promises.promise();


        /* Promise that returns when any employees are returned. */
        final Promise<Void> promise = Promises.any(promise1, promise2);


        promise.then(nil -> System.out.println("DONE!"));

        assertFalse("Not done yet", promise.complete());

        /** Call service. */
        employeeService.loadEmployee("id1", promise2);


        /** Wait some time. */
        //...

        assertTrue(promise.complete());
        assertTrue(promise.success());

We also support anyReplayPromise and anyBlockingPromise. A replay promise is a promise that executes on the caller's thread not the callee. A blocking promise is a promise that blocks until the callback returns. We only recommend using blocking promises for legacy integration and testing.

####Any API in Promises

...
public interface Promises {


    /**
     * Any promises must complete.
     *
     * @param promises promises
     * @return return containing promise
     */
    static Promise<Void> any(final Promise<?>... promises) {
        return new AnyPromise(promises);
    }

    /**
     * All promises must complete.
     *
     * @param promises promises
     * @param <T>      types of promise
     * @return return containing promise
     */
    static <T> Promise<Void> any(final List<Promise<T>> promises) {
        return new AnyPromise(promises.toArray(new Promise[promises.size()]));
    }


    /**
     * Any promises must complete.
     *
     * @param promises promises
     * @return return containing promise that is blocking.
     */
    static Promise<Void> anyBlocking(final Promise<?>... promises) {
        return new AnyBlockingPromise(promises);
    }


    /**
     * Any promises must complete.
     *
     * @param promises promises
     * @param <T>      types of promise
     * @return return containing promise that is blocking.
     */
    static <T> Promise<Void> anyBlocking(final List<Promise<T>> promises) {
        return new AnyBlockingPromise(promises.toArray(new Promise[promises.size()]));
    }


    /**
     * Any promises must complete.
     *
     * @param timeout  timeout
     * @param time     time
     * @param promises promises
     * @return returns replay promise so promise can be replayed in caller's thread.
     */
    static ReplayPromise<Void> anyReplay(final Duration timeout, long time,
                                         final Promise<?>... promises) {
        return new AnyReplayPromise(timeout, time, promises);
    }

    /**
     * Any promises must complete.
     *
     * @param timeout  timeout
     * @param time     time
     * @param promises promises
     * @param <T>      types of promise
     * @return returns replay promise so promise can be replayed in caller's thread.
     */
    static <T> ReplayPromise<Void> anyReplay(final Duration timeout, long time,
                                             final List<Promise<T>> promises) {
        return new AnyReplayPromise(timeout, time, promises.toArray(new Promise[promises.size()]));
    }

    /**
     * Any promises must complete.
     *
     * @param timeout  timeout
     * @param promises promises
     * @return returns replay promise so promise can be replayed in caller's thread.
     */
    static ReplayPromise<Void> anyReplay(final Duration timeout, final Promise<?>... promises) {
        return anyReplay(timeout, System.currentTimeMillis(), promises);
    }


    /**
     * Any promises must complete.
     *
     * @param timeout  timeout
     * @param promises promises
     * @param <T>      types of promise
     * @return returns replay promise so promise can be replayed in caller's thread.
     */
    static <T> ReplayPromise<Void> anyReplay(final Duration timeout, final List<Promise<T>> promises) {
        return anyReplay(timeout, System.currentTimeMillis(), promises.toArray(new Promise[promises.size()]));
    }

Example of using anyBlocking

    @Test
    public void testAnyBlocking() throws Exception {

        TestService testService = new TestService();

        Promise<Employee> promise1 = Promises.promise();
        Promise<Employee> promise2 = Promises.promise();

        final Promise<Void> promise = Promises.anyBlocking(promise1, promise2);

        assertFalse(promise.complete());

        testService.async(promise2);

        assertTrue(promise.success());

    }

Example of using anyReplay

    @Test
    public void testAnyReplay() throws Exception {

        TestService testService = new TestService();

        Promise<Employee> promise1 = Promises.promise();
        Promise<Employee> promise2 = Promises.promise();

        final ReplayPromise<Void> promise = Promises.anyReplay(Duration.ofMillis(1000),
                promise1, promise2);

        assertFalse(promise.complete());

        testService.async(promise2);


        for (int index = 0; index < 10; index++) {
            promise.check(System.currentTimeMillis());
            if (promise.complete()) break;
            Thread.sleep(10);

        }


        assertTrue(promise.complete());
        assertTrue(promise.success());

    }

Test Service

    public static class TestService {

        public void simple(Callback<Employee> callback) {
            callback.reply(new Employee("Rick"));
        }


        public void async(final Callback<Employee> callback) {

            new Thread(() -> {
                callback.reply(new Employee("Rick"));
            }).start();
        }


        public void asyncTimeout(final Callback<Employee> callback) {

            new Thread(() -> {
                try {
                    Thread.sleep(10_000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                callback.reply(new Employee("Rick"));
            }).start();
        }

        public void asyncError(final Callback<Employee> callback) {
            new Thread(() -> {
                callback.reject("Rick");
            }).start();
        }


        public void error(Callback<Employee> callback) {
            callback.reject("Error");
        }

        public void exception(Callback<Employee> callback) {
            callback.reject(new IllegalStateException("Error"));
        }
    }