Interesting map and flatMap observations - Future, Scala - scala

I noticed few interesting behaviour about map, flatMap and Future but I am not able to understand what is causing this behaviour
//I have 3 Future objects.
object ConcurrencyExample extends App {
val time = System.currentTimeMillis()
val future1 = Future{println("future1");1}
val future2 = Future{println("future2");2}
val future3 = Future{println("future3");3}
//I want to add 1,2 and 3. I can do it using flatMap
val result = future1 flatMap (f1=> future2.flatMap(f2 => future3.map(f3=> f3+f2+f1) ) )
result onComplete{
case Success(v)=>println("result is "+v)
case Failure(e) =>println("failed result:"+e)
}
Thread.sleep(1000)
}
result
future2
future1
future3
result is 6
If I change the code above to map, I get an empty List(). I am unable to track where this empty List came from?
val result = future1 map (f1=> future2.map(f2 => future3.map(f3=> f3+f2+f1) ) )
result
future3
future2
future1
result is List()
If I use only two Future objects and map, I get Success(3) and not an empty List()
val result = future1 map (f1=> future2.map(f2 => f2+f1) )
result
future3
future2
future1
result is Success(3)

In the first case the result return type is Future[Int], In the second case the result return type is Future[Future[...]] (some nested Future)
In the first case when you do the onComplete that is
val result: Future[Int] = ???
result onComplete { println }
The above code will return Success(1)
In the second case
val result: Future[Future[..]] = ???
result onComplete { println }
This may result unevaluated Future that is why you see List(). See the Scala repl output below. Look at the result type of Future { Thread.sleep(1000); 1 }
scala> import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.ExecutionContext.Implicits.global
scala> val f = Future { Thread.sleep(1000); 1 }
f: scala.concurrent.Future[Unit] = List()
scala> f onComplete { println }
Success(1)
Suggestion
Know the difference between flatMap and map and know when to use flatMap and map.

Related

Scala Future calling lazy method inside block is not working

Problem:
I am trying to call lazy function(function assigned to lazy val) inside Future block and it is not behaving as expected but when i execute the function directly inside the block it is working as expected. Not sure if am missing any.
Working Code:
Below is the code working as expected when i execute the method directly inside Future block
implicit val ec = ExecutionContext.fromExecutorService {
Executors.newFixedThreadPool(8)
}
def execute1() = {
Thread.sleep(4000); println("Completed 1!!!")
1
}
def execute2() = {
Thread.sleep(3000); println("Completed 2!!!")
2
}
def execute3() = {
Thread.sleep(2000); println("Completed 3!!!")
3
}
def execute4() = {
Thread.sleep(1000); println("Completed 4!!!")
4
}
val future1 : Future[Int] = Future.apply(execute1())
val future2 : Future[Int] = Future.apply(execute2())
val future3 : Future[Int] = Future.apply(execute3())
val future4 : Future[Int] = Future.apply(execute4())
val result = for { r1 <- future1
r2 <- future2
r3 <- future3
r4 <- future4
} yield {
println(r1+","+r2+","+r3+","+r4)
}
StdIn.readLine()
sys.exit()
When the above code is executed, the methods are executed in order "execute4,execute3,execute2,execute1" which is as expected.
Not Working Code:
In the above code, when i trying assigning the "execute" method to lazy variable and refer that variable inside Future block it is behaving differently. It is executed in 1,4,3,2 order.. Please see below code
implicit val ec = ExecutionContext.fromExecutorService {
Executors.newFixedThreadPool(8)
}
def execute1() = {
Thread.sleep(4000); println("Completed 1!!!")
1
}
def execute2() = {
Thread.sleep(3000); println("Completed 2!!!")
2
}
def execute3() = {
Thread.sleep(2000); println("Completed 3!!!")
3
}
def execute4() = {
Thread.sleep(1000); println("Completed 4!!!")
4
}
lazy val e1 = execute1()
lazy val e2 = execute2()
lazy val e3 = execute3()
lazy val e4 = execute4()
val future1 : Future[Int] = Future.apply(e1)
val future2 : Future[Int] = Future.apply(e2)
val future3 : Future[Int] = Future.apply(e3)
val future4 : Future[Int] = Future.apply(e4)
val result = for { r1 <- future1
r2 <- future2
r3 <- future3
r4 <- future4
} yield {
println(r1+","+r2+","+r3+","+r4)
}
StdIn.readLine()
sys.exit()
Expected Behavior: Since the functions(e1,e2,e3,e4) are referred as Lazy, it should be executed inside Future block upon calling and should behave same as the working code. Weird behavior i notice is it executes execute1() method synchronously and rest of the methods asynchronously.. Any guidance or suggestion will be great to me..
Output I am Expecting:
Regardless of "i execute the method inside Future block"(or) "make the method as lazy outside the Future block and call inside the Future block" should yield me the same result.. As per my example, the output i am expecting is "the order of method execution(asynchronously) as execute4(),execute3(),execute2() and execute(1)"
To simplify the example..
Future Execution is different in below two approach.. In both the approach, i am expecting same output
//Approach#1
def method() = {
}
Future{
method()
}
//Approach#2
lazy val lazyMethod = method()
Future {
lazyMethod()
}
Actually the code is working as expected. Let me explain.
First comes the for, when you did,
val result = for {
r1 <- future1
r2 <- future2
r3 <- future3
r4 <- future4
} yield {
println(r1+","+r2+","+r3+","+r4)
}
You are roughly doing,
val result =
future1.flatMap(r1 =>
future2.flatMap(r2 =>
future3.flatMap(r3 =>
future4.map(r4 =>
println(r1+","+r2+","+r3+","+r4)
)
)
)
)
Which means you are "accessing" the values computed by these futures only after you have accessed the value of the previous one.
Now comes the Future.apply which takes a body: => T as argument and gives you a Future[T] but the thing is that this body will start executing as soon as you create the future.
So, In your first implementation when you did,
val future1 : Future[Int] = Future.apply(execute1())
val future2 : Future[Int] = Future.apply(execute2())
val future3 : Future[Int] = Future.apply(execute3())
val future4 : Future[Int] = Future.apply(execute4())
All these futuresI's began executing your executeI's at this point. So, the println inside these executeI's will be executed x ms after this, irrespective of when you try to access the value inside any of these futures.
Now, comes the lazy. So when you declare something like this,
val laxy x = {
println("accessing lazy x")
5
}
The block will be executed only when you access x for the first time.
And when you are doing this,
val future1 : Future[Int] = Future.apply(e1)
val future2 : Future[Int] = Future.apply(e2)
val future3 : Future[Int] = Future.apply(e3)
val future4 : Future[Int] = Future.apply(e4)
You are still not "accessing" any of these lazy eI's but as you know that each future starts computing as soon as it is created. So when these futures start executing they will "access" these eI's.
To understand it better, lets change our executeI's as following,
def execute1() = {
println("Started 1!!! " + System.currentTimeMillis())
Thread.sleep(4000)
println("Completed 1!!! " + System.currentTimeMillis())
1
}
And you will notice that all of these eI's are executing sequentially.
This is because all these eI's will be evaluated in the thread where these were defined and not in the thread executing the Future. So these Thread.sleep will block the current thread and will be evaluated in a non-deterministic order (owing to some probable optimizations), which co-incidentally happens to be 1, 4, 3, 2.
But if you change the order of future to,
val future1 : Future[Int] = Future.apply(e1)
val future4 : Future[Int] = Future.apply(e4)
val future2 : Future[Int] = Future.apply(e2)
val future3 : Future[Int] = Future.apply(e3)
It will become 1, 3, 2, 4.

Waiting for another future to end to return a function

Let's say I have a function func1 that needs to return a Future with two integers. Each of the two values are returned by independent futures, like so:
def f1 = Future { 1 }
def f2 = Future { 2 }
def func1 : Future[(Int,Int)] = {
val future1 = f1
future1.map { result1 =>
result1 * 10
}
val future2 = f2
future2.map { result2 =>
result2 * 20
}
}
I need future1 wait until future2 ends (or vice versa) to return both results as (Int,Int). How can this be accomplished?
That's precisely what the zip method on futures does:
val futurePair: Future[(Int, Int)] = future1.zip(future2)
Note that if you haven't instantiated your futures before (say, if future1 and future2 are defs, not vals), this will run the two computations in parallel, while a for comprehension (or flatMap) would wait for the first one to succeed before starting the second one.
A for-comprehension is the best option here:
scala> import scala.concurrent.Future
import scala.concurrent.Future
scala> import concurrent.ExecutionContext.Implicits.global
import concurrent.ExecutionContext.Implicits.global
scala> def f1 = Future{1}
f1: scala.concurrent.Future[Int]
scala> def f2 = Future{2}
f2: scala.concurrent.Future[Int]
scala> for {result1 <- f1; result2 <- f2} yield (result1 * 10, result2 * 20)
res0: scala.concurrent.Future[(Int, Int)] = scala.concurrent.impl.Promise$DefaultPromise#71f67a79
More information can be found here and here.
Note: this will run the two Futures in sequence while Cyrille Corpet's solution will run them in parallel.
You can use a for-comprehension for futures that have already started like this:
val f1: Future[Int] = ???
val f2: Future[Int] = ???
val f3: Future[Int] = ???
val futureInts: Future[(Int, Int, Int)] = for {
result1 <- f1
result2 <- f2
result3 <- f3
} yield (result1, result2, result3)
If the futures were assigned to lazy vals or defs then this wouldn't work, because the futures would not have been started (if you start the futures inside the for comprehension, then they will be executed sequentially). Here is an example of starting them, and then waiting for them with for.
Example:
val f1: Future[Int] = Future {
println("starting f1")
Thread.sleep(1000)
1
}
val f2: Future[Int] = Future {
println("starting f2")
Thread.sleep(3000)
2
}
val f3: Future[Int] = Future {
println("starting f3")
Thread.sleep(2000)
3
}
val futureInts: Future[(Int, Int, Int)] = for {
result1 <- f1
result2 <- f2
result3 <- f3
} yield (result1, result2, result3)
futureInts.map {
case tuple => println(tuple)
}
Output:
starting f1 // These first
starting f3 // threes statements
starting f2 // happen right away.
(1,2,2) // Then this prints a three seconds later
In your case you could do this:
def func1 : Future[(Int,Int)] = {
// Start futures
val future1 = f1.map(_ * 10)
val future2 = f2.map(_ * 20)
// Wait for both futures, and return a tuple
for {
result1 <- future1
result2 <- future2
} yield (result1, result2)
}

Match on tuples within for comprehension

I am trying to write a function that returns a future. Within this future 3 other future functions are called, the third depends on the results of the first two. My instinct is to use a for comphrension, but when I try to match on the tuple I get this error:
value map is not a member of Object
Which refers to the match of (result1, result2) below
def future1 = Future { ... }
def future2 = Future { ... }
def future3(a, b): Future[T] = Future { .... }
def future4: Future[T] = {
for {
result1 <- future1
result2 <- future2
result3 <- (result1, result2) match {
case (x, y) => future3(result1, result2)
case (_, _) => ???
}
} yield result3
}
It can be solved by making whatever is under ??? return Future[T]

Future[Option[Future[Option[Boolean]] Simplifying Futures and Options?

I've been trying to simplify the way I do futures in Scala. I got at one point a Future[Option[Future[Option[Boolean]] but I've simplified it further below. Is there a better way to simplify this?
Passing a future of "failed" doesn't seem like the best way to do this. i.e. in the sequential world I simply returned "FAIL!!" any time it failed rather than continuing to the end. Are there other ways?
val doSimpleWork = Future {
//Do any arbitrary work (can be a different function)
true //or false
}
val doComplexWork = Future {
//Do any arbitrary work (can be a different function)
Some("result") //or false
}
val failed = Future {
//Do no work at all!!! Just return
false
}
val fut1 = doSimpleWork
val fut2 = doSimpleWork
val fut3 = (fut1 zip fut2).map({
case (true, true) => true
case _ => false
})
val fut4 = fut3.flatMap({
case true =>
doComplexWork.flatMap({
case Some("result") =>
doSimpleWork
case None =>
failed
})
case false =>
failed
})
fut4.map({
case true =>
"SUCCESS!!!"
case _ =>
"FAIL!!"
})
Note that in your example, because you're eagerly instantiating the Futures to a val, all of them will start executing as soon as you declare them (val x = Future {...}). Using methods instead will make the Futures execute only when they're requested by the chain of execution.
One way to avoid the further computation would be to throw an exception, then handle it with onFailure:
def one = future { println("one") ; Some(1) }
def two = future { println("two") ; throw new Exception("no!"); 2 }
def three = future { println("three") ; 3 }
val f = one flatMap {
result1 => two flatMap {
result2 => three
}
}
f onFailure {
case e: Exception =>
println("failed somewhere in the chain")
}
You can see here that "three" isn't supposed to be printed out, because we fail on two. This is the case:
one
two
failed somewhere in the chain
a "Monad transformer" is a construct which lets you combine the "effects" of two monads, the scalaz project provides several different monad transformers. My suggestion is that you can use the OptionT monad transformer to simplify your code if you also make use of the fact that Option[Unit] is isomorphic to Boolean (Some(()) == true and None == false). Here's a complete example:
import scalaz._
import Scalaz._
import scala.concurrent._
import ExecutionContext.Implicits.global
import scala.concurrent.duration._
object Foo {
// We need a Monad instance for Future, here is a valid one, or you can use the implementation
// in the scalaz-contrib project, see http://typelevel.org
implicit def futureMonad(implicit executor: ExecutionContext): Monad[Future] = new Monad[Future] {
override def bind[A, B](fa: Future[A])(f: A ⇒ Future[B]) = fa flatMap f
override def point[A](a: ⇒ A) = Future(a)
override def map[A, B](fa: Future[A])(f: A ⇒ B) = fa map f
}
// OptionT allows you to combine the effects of the Future and Option monads
// to more easily work with a Future[Option[A]]
val doSimpleWork : OptionT[Future,Unit] = OptionT(Future {
// Option[Unit] is isomorphic to Boolean
Some(()) //or None
})
val simpleFail : OptionT[Future,Unit] = OptionT(Future {
None
})
val doComplexWork: OptionT[Future,String] = OptionT(Future {
Some("result") //or None
})
val f1 = doSimpleWork
val f2 = doSimpleWork
val f3 = doComplexWork
val f4 = doSimpleWork
def main(argv: Array[String]) {
val result = for {
_ <- f1
// we don't get here unless both the future succeeded and the result was Some
_ <- f2
_ <- f3
r <- f4
} yield(r)
result.fold((_ => println("SUCCESS!!")),println("FAIL!!"))
// "run" will get you to the Future inside the OptionT
Await.result(result.run, 1 second)
}
}
You could try something like this, using for comprehensions to clean up the code a bit:
def doSimpleWork = Future{
//do some simple work
true
}
def doComplexWork = Future{
//do something complex here
Some("result")
}
val fut1 = doSimpleWork
val fut2 = doSimpleWork
val fut = for{
f1Result <- fut1
f2Result <- fut2
if (f1Result && f2Result)
f3Result <- doComplexWork
if (f3Result.isDefined)
f4Result <- doSimpleWork
} yield "success"
fut onComplete{
case Success(value) => println("I succeeded")
case Failure(ex) => println("I failed: " + ex.getMessage)
}
And if you really just wanted to print out "success" or "failed" at the end, you could change that last piece of code to:
fut.recover{case ex => "failed"} onSuccess{
case value => println(value)
}
Now, to explain what's going on. For starters, we've defined two functions that return Futures that are doing some async work. The doSimpleWork function will do some simple work and return a boolean success/fail indicator. The doComplexWork function will do something more complex (and time consuming) and return an Option[String] representing a result. We then kick off two parallel invocations of doSimpleWork before entering the for comprehension. In for for comp, we get the results of fut1 and fut2 (in that order) before checking if they were both successful. If not, we would stop here, and the fut val would be failed with a NoSuchElementException which is what you get when a condition like this fails in a for comp. If both were successful, we would continue on and invoke the doComplexWork function and wait for its result. We would then check its result and if it was Some, we would kick off one last invocation of doSimpleWork. If that succeeds, we would yield the string "success". If you check the type of the fut val, its of type Future[String].
From there, we use one of the async callback functions to check if the whole sequence of calls either made it all the way through (the Success case), or failed somewhere in the process (the Failure case), printing out something related to which case it hit. In the alternate final code block, we recover from any possible failure by returning the String "failed" "and then use just the onSuccess callback which will print either "success" or "failed" depending on what happened.

How to wait for several Futures?

Suppose I have several futures and need to wait until either any of them fails or all of them succeed.
For example: Let there are 3 futures: f1, f2, f3.
If f1 succeeds and f2 fails I do not wait for f3 (and return failure to the client).
If f2 fails while f1 and f3 are still running I do not wait for them (and return failure)
If f1 succeeds and then f2 succeeds I continue waiting for f3.
How would you implement it?
You could use a for-comprehension as follows instead:
val fut1 = Future{...}
val fut2 = Future{...}
val fut3 = Future{...}
val aggFut = for{
f1Result <- fut1
f2Result <- fut2
f3Result <- fut3
} yield (f1Result, f2Result, f3Result)
In this example, futures 1, 2 and 3 are kicked off in parallel. Then, in the for comprehension, we wait until the results 1 and then 2 and then 3 are available. If either 1 or 2 fails, we will not wait for 3 anymore. If all 3 succeed, then the aggFut val will hold a tuple with 3 slots, corresponding to the results of the 3 futures.
Now if you need the behavior where you want to stop waiting if say fut2 fails first, things get a little trickier. In the above example, you would have to wait for fut1 to complete before realizing fut2 failed. To solve that, you could try something like this:
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)
}
Now this works correctly, but the issue comes from knowing which Future to remove from the Map when one has been successfully completed. As long as you have some way to properly correlate a result with the Future that spawned that result, then something like this works. It just recursively keeps removing completed Futures from the Map and then calling Future.firstCompletedOf on the remaining Futures until there are none left, collecting the results along the way. It's not pretty, but if you really need the behavior you are talking about, then this, or something similar could work.
You can use a promise, and send to it either the first failure, or the final completed aggregated success:
def sequenceOrBailOut[A, M[_] <: TraversableOnce[_]](in: M[Future[A]] with TraversableOnce[Future[A]])(implicit cbf: CanBuildFrom[M[Future[A]], A, M[A]], executor: ExecutionContext): Future[M[A]] = {
val p = Promise[M[A]]()
// the first Future to fail completes the promise
in.foreach(_.onFailure{case i => p.tryFailure(i)})
// if the whole sequence succeeds (i.e. no failures)
// then the promise is completed with the aggregated success
Future.sequence(in).foreach(p trySuccess _)
p.future
}
Then you can Await on that resulting Future if you want to block, or just map it into something else.
The difference with for comprehension is that here you get the error of the first to fail, whereas with for comprehension you get the first error in traversal order of the input collection (even if another one failed first). For example:
val f1 = Future { Thread.sleep(1000) ; 5 / 0 }
val f2 = Future { 5 }
val f3 = Future { None.get }
Future.sequence(List(f1,f2,f3)).onFailure{case i => println(i)}
// this waits one second, then prints "java.lang.ArithmeticException: / by zero"
// the first to fail in traversal order
And:
val f1 = Future { Thread.sleep(1000) ; 5 / 0 }
val f2 = Future { 5 }
val f3 = Future { None.get }
sequenceOrBailOut(List(f1,f2,f3)).onFailure{case i => println(i)}
// this immediately prints "java.util.NoSuchElementException: None.get"
// the 'actual' first to fail (usually...)
// and it returns early (it does not wait 1 sec)
Here is a solution without using actors.
import scala.util._
import scala.concurrent._
import java.util.concurrent.atomic.AtomicInteger
// Nondeterministic.
// If any failure, return it immediately, else return the final success.
def allSucceed[T](fs: Future[T]*): Future[T] = {
val remaining = new AtomicInteger(fs.length)
val p = promise[T]
fs foreach {
_ onComplete {
case s # Success(_) => {
if (remaining.decrementAndGet() == 0) {
// Arbitrarily return the final success
p tryComplete s
}
}
case f # Failure(_) => {
p tryComplete f
}
}
}
p.future
}
You can do this with futures alone. Here's one implementation. Note that it won't terminate execution early! In that case you need to do something more sophisticated (and probably implement the interruption yourself). But if you just don't want to keep waiting for something that isn't going to work, the key is to keep waiting for the first thing to finish, and stop when either nothing is left or you hit an exception:
import scala.annotation.tailrec
import scala.util.{Try, Success, Failure}
import scala.concurrent._
import scala.concurrent.duration.Duration
import ExecutionContext.Implicits.global
#tailrec def awaitSuccess[A](fs: Seq[Future[A]], done: Seq[A] = Seq()):
Either[Throwable, Seq[A]] = {
val first = Future.firstCompletedOf(fs)
Await.ready(first, Duration.Inf).value match {
case None => awaitSuccess(fs, done) // Shouldn't happen!
case Some(Failure(e)) => Left(e)
case Some(Success(_)) =>
val (complete, running) = fs.partition(_.isCompleted)
val answers = complete.flatMap(_.value)
answers.find(_.isFailure) match {
case Some(Failure(e)) => Left(e)
case _ =>
if (running.length > 0) awaitSuccess(running, answers.map(_.get) ++: done)
else Right( answers.map(_.get) ++: done )
}
}
}
Here's an example of it in action when everything works okay:
scala> awaitSuccess(Seq(Future{ println("Hi!") },
Future{ Thread.sleep(1000); println("Fancy meeting you here!") },
Future{ Thread.sleep(2000); println("Bye!") }
))
Hi!
Fancy meeting you here!
Bye!
res1: Either[Throwable,Seq[Unit]] = Right(List((), (), ()))
But when something goes wrong:
scala> awaitSuccess(Seq(Future{ println("Hi!") },
Future{ Thread.sleep(1000); throw new Exception("boo"); () },
Future{ Thread.sleep(2000); println("Bye!") }
))
Hi!
res2: Either[Throwable,Seq[Unit]] = Left(java.lang.Exception: boo)
scala> Bye!
For this purpose I would use an Akka actor. Unlike the for-comprehension, it fails as soon as any of the futures fail, so it's a bit more efficient in that sense.
class ResultCombiner(futs: Future[_]*) extends Actor {
var origSender: ActorRef = null
var futsRemaining: Set[Future[_]] = futs.toSet
override def receive = {
case () =>
origSender = sender
for(f <- futs)
f.onComplete(result => self ! if(result.isSuccess) f else false)
case false =>
origSender ! SomethingFailed
case f: Future[_] =>
futsRemaining -= f
if(futsRemaining.isEmpty) origSender ! EverythingSucceeded
}
}
sealed trait Result
case object SomethingFailed extends Result
case object EverythingSucceeded extends Result
Then, create the actor, send a message to it (so that it will know where to send its reply to) and wait for a reply.
val actor = actorSystem.actorOf(Props(new ResultCombiner(f1, f2, f3)))
try {
val f4: Future[Result] = actor ? ()
implicit val timeout = new Timeout(30 seconds) // or whatever
Await.result(f4, timeout.duration).asInstanceOf[Result] match {
case SomethingFailed => println("Oh noes!")
case EverythingSucceeded => println("It all worked!")
}
} finally {
// Avoid memory leaks: destroy the actor
actor ! PoisonPill
}
This question has been answered but I am posting my value class solution (value classes were added in 2.10) since there isn't one here. Please feel free to criticize.
implicit class Sugar_PimpMyFuture[T](val self: Future[T]) extends AnyVal {
def concurrently = ConcurrentFuture(self)
}
case class ConcurrentFuture[A](future: Future[A]) extends AnyVal {
def map[B](f: Future[A] => Future[B]) : ConcurrentFuture[B] = ConcurrentFuture(f(future))
def flatMap[B](f: Future[A] => ConcurrentFuture[B]) : ConcurrentFuture[B] = concurrentFutureFlatMap(this, f) // work around no nested class in value class
}
def concurrentFutureFlatMap[A,B](outer: ConcurrentFuture[A], f: Future[A] => ConcurrentFuture[B]) : ConcurrentFuture[B] = {
val p = Promise[B]()
val inner = f(outer.future)
inner.future onFailure { case t => p.tryFailure(t) }
outer.future onFailure { case t => p.tryFailure(t) }
inner.future onSuccess { case b => p.trySuccess(b) }
ConcurrentFuture(p.future)
}
ConcurrentFuture is a no overhead Future wrapper that changes the default Future map/flatMap from do-this-then-that to combine-all-and-fail-if-any-fail. Usage:
def func1 : Future[Int] = Future { println("f1!");throw new RuntimeException; 1 }
def func2 : Future[String] = Future { Thread.sleep(2000);println("f2!");"f2" }
def func3 : Future[Double] = Future { Thread.sleep(2000);println("f3!");42.0 }
val f : Future[(Int,String,Double)] = {
for {
f1 <- func1.concurrently
f2 <- func2.concurrently
f3 <- func3.concurrently
} yield for {
v1 <- f1
v2 <- f2
v3 <- f3
} yield (v1,v2,v3)
}.future
f.onFailure { case t => println("future failed $t") }
In the example above, f1,f2 and f3 will run concurrently and if any fail in any order the future of the tuple will fail immediately.
You might want to checkout Twitter's Future API. Notably the Future.collect method. It does exactly what you want: https://twitter.github.io/scala_school/finagle.html
The source code Future.scala is available here:
https://github.com/twitter/util/blob/master/util-core/src/main/scala/com/twitter/util/Future.scala
You can use this:
val l = List(1, 6, 8)
val f = l.map{
i => future {
println("future " +i)
Thread.sleep(i* 1000)
if (i == 12)
throw new Exception("6 is not legal.")
i
}
}
val f1 = Future.sequence(f)
f1 onSuccess{
case l => {
logInfo("onSuccess")
l.foreach(i => {
logInfo("h : " + i)
})
}
}
f1 onFailure{
case l => {
logInfo("onFailure")
}