Em vez disso, você poderia usar uma compreensão para a seguinte:
val fut1 = Future{...}
val fut2 = Future{...}
val fut3 = Future{...}
val aggFut = for{
f1Result <- fut1
f2Result <- fut2
f3Result <- fut3
} yield (f1Result, f2Result, f3Result)
Neste exemplo, os futuros 1, 2 e 3 são iniciados em paralelo. Então, na para compreensão, esperamos até que os resultados 1 e 2 e depois 3 estejam disponíveis. Se 1 ou 2 falhar, não esperaremos mais por 3. Se todos os 3 forem bem-sucedidos, o aggFut
val manterá uma tupla com 3 slots, correspondendo aos resultados dos 3 futuros.
Agora, se você precisa do comportamento em que deseja parar de esperar se, digamos, fut2 falhar primeiro, as coisas ficam um pouco mais complicadas. No exemplo acima, você teria que esperar que fut1 fosse concluído antes de perceber que fut2 falhou. Para resolver isso, você pode tentar algo assim:
val fut1 = Future{Thread.sleep(3000);1}
val fut2 = Promise.failed(new RuntimeException("boo")).future
val fut3 = Future{Thread.sleep(1000);3}
def processFutures(futures:Map[Int,Future[Int]], values:List[Any], prom:Promise[List[Any]]):Future[List[Any]] = {
val fut = if (futures.size == 1) futures.head._2
else Future.firstCompletedOf(futures.values)
fut onComplete{
case Success(value) if (futures.size == 1)=>
prom.success(value :: values)
case Success(value) =>
processFutures(futures - value, value :: values, prom)
case Failure(ex) => prom.failure(ex)
}
prom.future
}
val aggFut = processFutures(Map(1 -> fut1, 2 -> fut2, 3 -> fut3), List(), Promise[List[Any]]())
aggFut onComplete{
case value => println(value)
}
Agora isso funciona corretamente, mas o problema é saber qual Future
remover do Map
quando um foi concluído com êxito. Contanto que você tenha alguma maneira de correlacionar adequadamente um resultado com o Futuro que gerou esse resultado, algo assim funciona. Ele apenas recursivamente continua removendo Futuros concluídos do Mapa e, em seguida, chamando Future.firstCompletedOf
os restantes Futures
até que não haja mais nenhum, coletando os resultados ao longo do caminho. Não é bonito, mas se você realmente precisa do comportamento de que está falando, isso ou algo semelhante pode funcionar.