Scala futures and `andThen` exception propagation
Don't throw
exception in Future.successful {}
.
here is the correct way to do it
Future { throw new RuntimeException("test") } andThen
{ case _ => println("test") }
You can understand the use of andThen
using the following line of code
Future.successful { 1 } andThen { case _ => "foo" }
REPL
@ Future.successful { 1 } andThen { case _ => "foo" }
res7: Future[Int] = Success(1)
REPL
@ Future.successful { 1 } andThen { case _ => println("foo") }
foo
res8: Future[Int] = Success(1)
REPL
@ val result = Future.successful { 1 } andThen { case _ => "foo" }
result: Future[Int] = Success(1)
In the above examples
We can see that partial function after andthen is executed but partial function return type is ignored. Finally the resultant output is result of the Future
which is the Future[Int]
This means addThen
is used for executing side effecting function just after the Future
is completed.
When Future is a Failure
REPL
@ val result = Future { throw new Exception("bar") } andThen { case _ => "foo" }
result: Future[Nothing] = Failure(java.lang.Exception: bar)
REPL
@ val result = Future { throw new Exception("bar") } andThen { case _ => println("foo") }
foo
result: Future[Nothing] = Failure(java.lang.Exception: bar)
Same is the case when future is a failure. Code after andThen executes and but the result of the code after andThen is ignored and final result is the Future result.
So andThen
is used for running side effecting code as soon as Future completes. andThen
also keeps the final output as Future
s output.
This is how andThen
is implemented in Standard library.
andThen
resides inside the Future
class
def andThen[U](pf: PartialFunction[Try[T], U])(implicit executor: ExecutionContext): Future[T] = {
val p = Promise[T]()
onComplete {
case r => try pf.applyOrElse[Try[T], Any](r, Predef.conforms[Try[T]]) finally p complete r
}
p.future
}
1) Applies the side-effecting function to the result of this future, and returns a new future with the result of this future.
Yes
pf
is the side effecting code because its output type is not used (cannot be used). p.future
is the new future he is talking about.
Promise
is completed with the previous Future
result (look at the implementation of addThen
above)
inside the finally block p complete r
means new Future is created using p.future
and it is completed using the previous future result which is r
2) This method allows one to enforce that the callbacks are executed in a specified order.
Yes. You can chain multiple callbacks using multiple andThen
calls and these callbacks are executed one after another in the order of andThen
calls. This is compared to the onComplete
methods that you can use it multiple times to register multiple callbacks, but the order of these callbacks is uncertain.
3) Note that if one of the chained andThen callbacks throws an exception, that exception is not propagated to the subsequent andThen callbacks. Instead, the subsequent andThen callbacks are given the original value of this future.
Yes
r
which is the result of the previous future is given to pf
(look at the andThen code above)