I'm using json4s with play framework and I have some places where I'll run a post/get request in a future, then onSuccess parse the response in to an object and have the actor send it back to itself.. Here's an example:
WS.url(authUrl).post("username=admin&password=admin") map {
response =>
self ! (parse(response.body) \ "body").extract[AuthObject]
}
and then back in the receive method:
case AuthObject(_, sid) => //handle authorization token
Is this bad practice? What's the correct way to go about this? The advantage I see is being able to have your actors data flow handled by a single control structure, but of course I could be wrong in saying that's an advantage.
The recommended way to send future results to actors is to use the pipe
pattern. You code would then look like this:
def receive:Reveice= {
case authUrl:String =>
val authObjectF=WS.url(authUrl).post("username=admin&password=admin") map { response =>
(parse(response.body) \ "body").extract[AuthObject]
}
authObjectF pipeTo self
}
The reason this is considered superior to map {x => self ! x }
is error handling. If you don't handle the error cases, they will simply be silently discarded.
Using the pipe
pattern, the errors will be wrapped in a akka.actor.Status.Failure
and sent to the destination actor (in this case to self
) in place of the result.
Piping the result of a future to self is a common pattern, possibly used in conjunction with context.become/unbecome and stash to create state machines.
It is still very easy to close over actor internal mutable state in a map/flatmap and break the concurrency guarantees of the actor model in doing so. If you are manipulating futures in actors I strongly suggest reading this http://doc.akka.io/docs/akka/2.3.2/general/jmm.html#jmm-shared-state if you haven't done so already.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With