scala Seq[Future] to Future[Seq]
I have an API which gives me Future[Int]
, since I have to operate it on sequence of items, my resultant would be Seq[Future[Int]]
.
When I expose my API it makes more sense to have Future[Seq[Int]]
instead of Seq[Future[Int]]
.
But the trick here is when I translate Seq[Future] to Future[Seq], future has to two states
1) Failure
2) Success
What if the Seq[Future] has one Future.Failure
. Here's the example
scala> val task : Seq[Future[Int]] = (1 to 3).map(x => if (x == 3) Future.failed(new RuntimeException("error")) else Future(x))
task: Seq[scala.concurrent.Future[Int]] = Vector(Future(Success(1)), Future(Success(2)), Future(Failure(java.lang.RuntimeException: error)))
scala> Future.sequence(task)
res6: scala.concurrent.Future[Seq[Int]] = Future(<not completed>)
scala> res6
res7: scala.concurrent.Future[Seq[Int]] = Future(Failure(java.lang.RuntimeException: error))
The problem here is that Future.sequence is Future.Failure if it finds one single failure in a sequence.
Solution
scala> import scala.util.Try
import scala.util.Try
scala> import scala.util.Success
import scala.util.Success
scala> import scala.util.Failure
import scala.util.Failure
scala> val task: Seq[Future[Try[Int]]] = (1 to 3).map(x => if (x == 3) Future.successful(Failure(new RuntimeException("error"))) else Future(Success(x)))
task: Seq[scala.concurrent.Future[scala.util.Try[Int]]] = Vector(Future(Success(Success(1))), Future(Success(Success(2))), Future(Success(Failure(java.lang.RuntimeException: error))))
scala> Future.sequence(task)
res8: scala.concurrent.Future[Seq[scala.util.Try[Int]]] = Future(<not completed>)
scala> res8
res9: scala.concurrent.Future[Seq[scala.util.Try[Int]]] = Future(Success(Vector(Success(1), Success(2), Failure(java.lang.RuntimeException: error))))
Also, I can filter failures now,
scala> res8.map(_.filter(_.isSuccess))
res11: scala.concurrent.Future[Seq[scala.util.Try[Int]]] = Future(<not completed>)
scala> res11
res12: scala.concurrent.Future[Seq[scala.util.Try[Int]]] = Future(Success(Vector(Success(1), Success(2))))
Now the result can be simplified to Future[Seq]
,
scala> res8.map(_.filter(_.isSuccess).map(_.get))
res13: scala.concurrent.Future[Seq[Int]] = Future(<not completed>)
scala> res13
res14: scala.concurrent.Future[Seq[Int]] = Future(Success(Vector(1, 2)))
Written by Prayag Upd
Related protips
Have a fresh tip? Share with Coderwall community!
Post
Post a tip
Best
#Scala
Authors
Sponsored by #native_company# — Learn More
#native_title#
#native_desc#