Is there a better way for cancelling a chain of futures in java?

Viewed 173

In scala with twitter Futures, I would simply do this and it would cancel a whole chain of futures (via interrupts) by default PREVENTING unecessary work being done. (CODE WRITTEN in JAVA though to make things easier)

    private CompletableFuture<Integer> startProcess(int i) {
        CompletableFuture<Integer> future1 = remoteCall(5);
        CompletableFuture<Integer> future2 = future1.thenCompose(s -> remoteCall(10));
        CompletableFuture<Integer> future3 = future2.thenCompose(s -> remoteCall(15));
        CompletableFuture<Integer> future4 = future3.thenCompose(s -> remoteCall(20));
        return future4;
    }

All futures above would be cancelled in scala UNLESS some interrupt handler is installed on one of them(which I might do in a forking case but that is irrelevant for this post).

In java, I have to do this nastiness it seems (but I am wondering if there is a better way)..

public class FutureTest {

    private Executor exec = Executors.newFixedThreadPool(10);

    public static void main(String[] args) {
        new FutureTest().start();
    }


    private void start() {
        CompletableFuture<Integer> f = startProcess(5);

        f.cancel(false);
    }


    private CompletableFuture<Integer> startProcess(int i) {
        CompletableFuture<Integer> future1 = remoteCall(5);
        CompletableFuture<Integer> future2 = future1.thenCompose(s -> remoteCall(10));
        CompletableFuture<Integer> future3 = future2.thenCompose(s -> remoteCall(15));
        future3.exceptionally(t -> {
            if(t instanceof CancellationException) {
                future2.cancel(false);
                t.printStackTrace();
            }
            return null;
        });

        CompletableFuture<Integer> future4 = future3.thenCompose(s -> remoteCall(20));
        future4.exceptionally(t -> {
            if(t instanceof CancellationException) {
                future3.cancel(false);
                t.printStackTrace();
            }
            return null;
        });

        return future4;
    }


    public CompletableFuture<Integer> remoteCall(int value) {
        CompletableFuture<Integer> future = new CompletableFuture<Integer>();
        exec.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println("RUnning task="+value);

                try {
                    Thread.sleep(5000);
                    future.complete(value+4);
                } catch (InterruptedException e) {
                    future.completeExceptionally(e);
                }

            }
        });

        return future;
    }

}

It seems to me that this is a big deficiency of java futures because 'most' of the time, in microservices you just chain a few remote calls to happen and if some client disconnects causing me to cancel the top level future, MOST of the time, I want the whole chain to cancel so we don't send requests to the DB's that will never respond to clients anyways.

Of course, you may have future1.thenApply(doSomething1) and future1.thenApply(doSomething2) so you can do 2 things in parallel BUT that is where interrupts come in. The default case should be to cancel everything up the chain of futures.

I guess as a side note, every time I see java try to take something that someone did in open source like logging, they completely put in a very minimal implementation that is way less usable than the original like them trying to create java.util.logging to replace log4j but of course log4j (and no slf4j) was way way better :(.

I am wondering if we need to create an open source CompletableFuture that actually works for

  • The above cancel case
  • Having a Local.java (like the Local.scala) that follows the request through like a ThreadLocal does so the MDC in slf4j works with CompletableFutures! (Currently MDC in slf4j only works with scala twitter futures). It breaks in java's CompletableFutures losing the state so log.info() can't grab the MDC data.

There is some great info and a whole section on interruption/cancellation in this article https://twitter.github.io/finagle/guide/developers/Futures.html regarding twitter futures and java futures.

thanks for any insight on this. Dean

0 Answers
Related