In Scala, I can use Await
to wait for a future to complete. However, if I have registered a callback to run upon completion of that future, how can I wait not
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration.Duration
import scala.concurrent.{ Await, Future }
import scala.util._
object Main {
def main(args: Array[String]): Unit = {
val f1: Future[Int] = Future(0)
val f2 = f1 andThen {
case Success(v) =>
Thread.sleep(10000)
println("The program waited patiently for this callback to finish.")
case Failure(e) =>
println(e)
}
Await.ready(f1, Duration.Inf)
println("F1 is COMPLETED")
Await.ready(f2, Duration.Inf)
println("F2 is COMPLETED")
}
}
prints:
F1 is COMPLETED
The program waited patiently for this callback to finish.
F2 is COMPLETED
Using promises is even more clear:
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration.Duration
import scala.concurrent._
import scala.util._
object Main {
def main(args: Array[String]): Unit = {
val f: Future[Int] = Future(0)
val p = Promise[Unit]()
p.future.onSuccess { case _ =>
println("The program waited patiently for this callback to finish.")
}
f.onSuccess { case _ =>
Thread.sleep(10000)
p.success(())
}
Await.ready(f, Duration.Inf)
println("F is COMPLETED")
Await.ready(p.future, Duration.Inf)
println("P is COMPLETED")
}
}
prints:
F is COMPLETED
P is COMPLETED
The program waited patiently for this callback to finish.
Don't use an onSuccess callback, but instead do the side effect in a Future.map call. That way, you have a Future[Unit] to use Await on.
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration.Duration
import scala.concurrent.{ Await, Future }
object Main {
def main(args: Array[String]): Unit = {
val f: Future[Int] = Future(0)
val f2: Future[Unit] = f.map { x =>
Thread.sleep(10000)
println("The program waited patiently for this callback to finish.")
}
Await.ready(f2, Duration.Inf)
}
}
Note that if you want to execute a side effect only in case of success (like in your example), map is appropriate. If you want to execute a side effect also in case of failure, andThen is the right method to use. See this post from Roland Kuhn on scala-user.
Also, please don't use Thread.sleep anywhere near production code.