In scala concurrent package, there is onComplete
method which returns nothing while in akka-http
directives, it returns the Directive1.
Is that the only difference? I sometimes got confused on those two methods.
In scala concurrent package, there is onComplete
method which returns nothing while in akka-http
directives, it returns the Directive1.
Is that the only difference? I sometimes got confused on those two methods.
These methods are different in what they aim to accomplish, but they are related in that the akka http onComplete
is meant to work with the completion of a Future
in order to complete the routing of a request.
The concurrent onComplete
is a method on a Future
that is meant to perform some sort of side effecting when the Future
has completed. There are a lot of other methods on a Future
like map
, flatMap
and filter
that will produce another Future
as you go through a series of transforms, but onComplete
returns nothing, and is sort of a "dead end" in the processing of that Future
.
An example of using onComplete
while also showing how something like map
can be used to change the Future
is as follows:
val fut1 = Future{"1"} // A Future[String]
val fut2 = fut1.map(_.toInt) // Now a Future[Int]
fut2.onComplete{
case util.Success(i) => println(s"success: $i")
case util.Failure(ex) => ex.printStackTrace()
}
val badFut1 = Future{"A"}
val badFut2 = badFut.map(_.toInt) //Will be failed
badFut2.onComplete{
case util.Success(i) => println(s"success: $i")
case util.Failure(ex) => ex.printStackTrace()
}
In the first case, we will hit the success case as "1" can be mapped into an Int. In the second example, we will hit the error case as "A" cannot be mapped to an Int. Either way, you can see that something like map
can be used to create a new transformed future while onComplete
can be used to do something based on the final result of that Future
.
In Akka Http, you sometimes need to create Route
definitions that need to do something asynchronously. In that case, you need to complete the route when that asynchronous task completed. A Route
itself needs to be fully defined in order to compile, so you can't leverage the existing onComplete
on a Future
because that returns nothing and that would render the definition of that Route
as incomplete. Therefore, the guys at Akka defined an onComplete
directive that will snap into a routing tree and work with a Future
, returning a Directive
that will fully define the tree for that Route
as oppose to leaving it open ended as the Future.onComplete
would. An example:
val myRoute =
get{
val fut = myActor ? "foo"
onComplete(foo){
case util.Success(_) => complete(StatusCodes.OK)
case util.Failure(ex) => complete(StatusCodes.InternalServerError)
}
}
So here, I'm making a request to an Actor
using ask (?)
and I get a Future
back. I still need to produce something that completes the Route
I am defining. If I did something like this:
val myRoute =
get{
val fut = myActor ? "foo"
fut.onComplete{
case util.Success(_) => complete(StatusCodes.OK)
case util.Failure(ex) => complete(StatusCodes.InternalServerError)
}
}
It worn't work because the onComplete
here is the one from the Future
and not the directive, and that returns Unit
and my Route
won't be full defined and won't compile.
So the onComplete
directive is there to allow you to define a Route
based on the completion of a Future
which you can't do properly with the pre-existing onComplete
from Future
itself.