I was hoping code like follows would wait for both futures, but it does not.
object Fiddle {
val f1 = Future {
throw new Throwable("baaa") // emulating a future that bumped into an exception
}
val f2 = Future {
Thread.sleep(3000L) // emulating a future that takes a bit longer to complete
2
}
val lf = List(f1, f2) // in the general case, this would be a dynamically sized list
val seq = Future.sequence(lf)
seq.onComplete {
_ => lf.foreach(f => println(f.isCompleted))
}
}
val a = FuturesSequence
I assumed seq.onComplete
would wait for them all to complete before completing itself, but not so; it results in:
true
false
.sequence
was a bit hard to follow in the source of scala.concurrent.Future, I wonder how I would implement a parallel that waits for all original futures of a (dynamically sized) sequence, or what might be the problem here.
Edit: A related question: https://worldbuilding.stackexchange.com/questions/12348/how-do-you-prove-youre-from-the-future :)
A
Future
produced byFuture.sequence
completes when either:The second point is what's happening in your case, and it makes sense to complete as soon as one of the wrapped
Future
has failed, because the wrappingFuture
can only hold a singleThrowable
in the failure case. There's no point in waiting for the other futures because the result will be the same failure.This is an example that supports the previous answer. There is an easy way to do this using just the standard Scala APIs.
In the example, I am creating 3 futures. These will complete at 5, 7, and 9 seconds respectively. The call to
Await.result
will block until all futures have resolved. Once all 3 futures have completed,a
will be set toList(5,7,9)
and execution will continue.Additionally, if an exception is thrown in any of the futures,
Await.result
will immediately unblock and throw the exception. Uncomment theException(...)
line to see this in action.We can enrich
Seq[Future[T]]
with its ownonComplete
method through an implicit class:Then, in your particular MWE, you can do:
This solution has the advantage of allowing you to call an
onComplete
on a sequence of futures as you would on a single future.One common approach to waiting for all results (failed or not) is to "lift" failures into a new representation inside the future, so that all futures complete with some result (although they may complete with a result that represents failure). One natural way to get that is lifting to a
Try
.Twitter's implementation of futures provides a
liftToTry
method that makes this trivial, but you can do something similar with the standard library's implementation:Now
Future.sequence(lifted)
will be completed when every future is completed, and will represent successes and failures usingTry
.And so, a generic solution for waiting on all original futures of a sequence of futures may look as follows, assuming an execution context is of course implicitly available.