Do Scala futures support for non-blocking combinators such as firstNCompletedOf and firstNSuccCompletedOf?

Viewed 101

For instance, Folly supports the non-blocking combinator collectN which can be found here https://github.com/facebook/folly/blob/master/folly/futures/helpers.h

It does not provide a non-blocking combinator collectNWithoutException which would only collect successful futures similiar to collectAny but for more than one resulting future.

Scala seems to provide only firstCompletedOf which would be collectN with n == 1.

How can I easily implement these non-blocking combinators if Scala does not support them? I would like to use the existing combinators for the implementation.

2 Answers

This is not practical for big number of futures, but a demonstration of available combinators

  def firstNCompleted[T](n: Int, futures: List[Future[T]])(implicit executor: ExecutionContext): Future[List[T]] =
    Future.firstCompletedOf(futures.combinations(n).map(Future.sequence(_)))
  • creates all combinations of n futures Iterator[List[Future[T]]]
  • sequences each combination into Future of resulting list Iterator[Future[List[T]]]
  • returns first completed Future[List[T]]

Here is collectN:

def collectN[T](n: Int, futures: List[Future[T]]): Future[List[T]] =  {
  val promise = Promise[List[T]]
  var result:List[T] = Nil
  futures.foreach {
     _.onComplete { 
       case _ if result.length >= n => 
       case Success(t) => synchronized {            
         result = t :: result
         if(result.length == n) promise.success(result.reversed.take(n))          
       }
       case Failure(x) => promise.failure(x) 
     }
  }
  promise.future
}

Note, that it returns a Future that will never complete if the number of input futures is less than n (and they all succeed). You can modify it trivially to keep waiting until N successes rather than aborting after first failure, but that would also end up waiting forever if less than N of futures end up succeeding. To avoid that, you could count the number of the ones that have completed, and bail out after it reaches the size of the original list.

Related