Search code examples
javascalatwitterfuturefinagle

Twitter Future timeout doesn't apply to the whole flatMap chain


I'm writing a server end program using Twitter Finagle. I do not use the full Twitter server stack, just the part that enables asynchronous processing (so Future, Function, etc). I want the Future objects to have timeouts, so I wrote this:

Future<String> future = Future.value(some_input).flatMap(time_consuming_function1);
future.get(Duration.apply(5, TimeUnit.SECONDS));

time_consuming_function1 runs for longer than 5 seconds. But future doesn't time out after 5 seconds and it waits till time_consuming_function1 has finished.

I think this is because future.get(timeout) only cares about how long the future took to create, not the whole operation chain. Is there a way to timeout the whole operation chain?


Solution

  • Basically if you call map/flatMap on a satisfied Future, the code is executed immediately.

    In your example, you're satisfying your future immediately when you call Future.value(some_input), so flatMap executes the code immediately and the call to get doesn't need to wait for anything. Also, everything is happening in one thread. A more appropriate use would be like this:

    import scala.concurrent.ops._
    import com.twitter.conversions.time._
    import com.twitter.util.{Future,Promise}
    
    val p = new Promise[String]
    val longOp = (s: String) => { 
      val p = new Promise[String]
      spawn { Thread.sleep(5000); p.setValue("Received: " + s) }
      p 
    }
    val both = p flatMap longOp
    both.get(1 second)  // p is not complete, so longOp hasn't been called yet, so this will fail
    p.setValue("test")  // we set p, but we have to wait for longOp to complete
    both.get(1 second)  // this fails because longOp isn't done
    both.get(5 seconds)  // this will succeed