2

My practice in this situation is to use .sequence to turn an F[G[A]] to a G[F[A]]. Then use Await.result(future_of_a_list, time_out) to get the results. However, there might be one task that takes a long time and times out. In this case, I still wanna get the rest of the results (while running all the tasks in parallel). Is it possible? How to do it?

Thanks

huoenter
  • 512
  • 3
  • 16
  • I think this might help: http://stackoverflow.com/questions/20874186/scala-listfuture-to-futurelist-disregarding-failed-futures – Marko Švaljek Jan 16 '17 at 22:29
  • @MarkoŠvaljek Thanks for the comment. But I don't think it's the issue. The TimeOut exception is not thrown by the Future execution. You either block on each future (sequential execution?) or block on the future list (the TimeOut happens outside of the Future). – huoenter Jan 16 '17 at 22:33
  • @MarkoŠvaljek I've already lifted the tasks to Try[_]. – huoenter Jan 16 '17 at 22:34

2 Answers2

1

Well, you can wrap each Await in another Future:

import scala.concurrent.{Await, Future}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
import scala.util.Success

scala> val s = Seq(Future(1), Future(2), Future { Thread.sleep(2000); 3 })
s: Seq[scala.concurrent.Future[Int]] = List(Future(Success(1)), Future(Success(2)), Future(<not completed>))

scala> val fs = Future.traverse(s)(f => 
         Future(Await.result(f, 1 second)).transform(Success(_)))
fs: scala.concurrent.Future[Seq[scala.util.Try[Int]]] = Future(<not completed>)

scala> Await.result(fs, Duration.Inf)
res2: Seq[scala.util.Try[Int]] = List(Success(1), Success(2), Failure(java.util.concurrent.TimeoutException: Futures timed out after [1 second]))
Kolmar
  • 14,086
  • 1
  • 22
  • 25
0

I agree with @Kolmar 's idea. Just the transform() in his solution is new the Scala 2.12.x version while in 2.11.x it has a different signature. I tried to upgrade but ran into dependency problems. I found my way around using the 2.11.x's fallbackTo. Since my Await.result(f, 1 second)) will return a scalaz.Validation[Throwable, T], it also works this way:

val fs = Future.traverse(s)(f => 
     Future(Await.result(f, 1 second)).fallbackTo(Future(Failure(new TimeoutException())))
huoenter
  • 512
  • 3
  • 16