What is the proper way to chain Akka Actor Ask calls? - scala

I'm using the Play Framework with scala. I'm new to scala, akka, and play.
This is my actor system. I'm not sure I'm doing this right, but I have 2 routers. 1 for Actor A, and 1 for Actor B:
val system = ActorSystem("ActionSystem")
val actorARouter = system.actorOf(Props[ActionParser].withRouter(
SmallestMailboxRouter(Runtime.getRuntime.availableProcessors())), name = "actorARouter")
val actorBRouter = system.actorOf(Props[ActionDispatcher].withRouter(
SmallestMailboxRouter(Runtime.getRuntime.availableProcessors())), name = "actorBRouter")
This is the current setup that I have:
The play framework provides a Controller for me that receives a http rest call with some json. Whenever the Controller receives a rest call, I do an ask sends the json to a router for Actor A. Here is what that looks like:
(actorARouter ? request.body.asJson.get).map {
case m: controllers.HttpMessages.OK => Ok(m.body)
case m: controllers.HttpMessages.HttpResponse => Status(m.status)(m.body)
}
Actor A then parses the json into a Seq of objects and then sends them via an ask to Actor B. Actor B is supposed to eventually process those by sending them to other actors, but for now is just returning generic responses.
The generic responses are being received back by ActorA via the future, then being parsed to JSON and then returned to the Controller via an OK response... or at least that's what is supposed to happen.
What's happening:
So what's happening is the controller sends to ActorA, ActorA sends to ActorB. ActorB sends generic responses to ActorA. ActorA parses generic responses into JSON and tries to do sender ! OK(json) but I get a message in the console saying it wasn't delivered as it's a "dead letter". when I debug into it when I look at sender, sender is a reference to the actor akka://ActionSystem/deadLetters
My questions:
Obviously I'm doing something wrong. Maybe I shouldn't be chaining these actors responses together like this. Again, I mentioned I only had plans to further this by having ActorB send out requests to other actors.
When I do an ask in an actor, that doesn't hog that thread and stop it from processing other messages while it's waiting for a response does it?
EDIT:
I found out I can save a reference to the sender for later use, and then send to that, and that seems to fix the dead letter problem. But I'm still very uncertain if this is the right way to be doing things. It feels like every time I'm adding another layer of actors 10's of milliseconds are being added onto my response time. Perhaps that's due to other factors though.

Without looking at your code, I cannot really comment on what caused the dead letter, from your edit I guess you closed over sender() instead of assigning it to a variable and closing over that.
To respond to your questions:
It is much easier to construct message flows with actors if you only use fire-and-forget messages. The ask Pattern is useful in some cases, but most of the time you should try to avoid it. What you can do instead is to pass the original sender along through your actors by using forward instead of tell. This way a response can be generated by the last actor in your message flow. The first actor only needs the code to handle the response, and does not need to care about generating the response. Nice separation of concerns right there. If you need to aggregate several responses in order to send out a single response afterwards, you can also use a temporary actor that all other actors will send their response to, and that knows the orignal sender. Temporary actors need to be stopped after doing their work.
As far as I know the ask pattern is asynchronous and uses temporary actors internally. However, if you wait for the result of the future in your actor, that will block that actor, and it will not be able to process further messages. A nice method to use the ask pattern is in combination with the pipeTo Pattern, which you can use to send the result of ask to an actor (usally self)

Related

Aggregating multiple child actor responses in Akka Typed

I'm currently porting an Akka Classic app to Akka Typed. I have the following components:
HttpService - Not an Actor
JobDispatcher - An Actor
JobWorker - Child actor of JobDispatcher
The JobDispatcher is a singleton actor that orchestrates jobs. Each JobWorker is responsible for one "job" and knows the job's status.
The HTTP service will make an Ask to JobDispatcher, called GetJobStatuses.
The JobDispatcher will then Ask each of the JobWorkers what their status is, aggregate the results into a list, and reply to HttpService.
The way I did this in Akka Classic was to have JobDispatcher do all the Asks, put the Futures into a list of Futures, and then transform that into a Future of Lists, and when that aggregate Future completed, I would send the results to HttpService. It looked something like this:
val statusFutures: Seq[Future[JobStatus]] = jobWorkers map (jobWorker => (jobWorker ? GetJobStatus).mapTo[JobStatus])
val aggregateFuture: Future[Seq[SearchStatus]] = Future.sequence(statusFutures)
val theSender = context.sender()
aggregateFuture onComplete {
case Success(jobStatuses: Seq[JobStatus]) => {
theSender ! jobStatuses
}
case Failure(exception) => {
theSender ! exception
}
}
So, now that we're moving to Akka Typed, we're not supposed to use Futures / onComplete, but instead turn the Ask response into a message back ourself (JobDispatcher in this case). This is fairly straightforward for simple situations where I'm Asking one other actor for one reply. But in this case, I have a whole list of child actors from which I need to compile their responses.
The only thing I can think of is to make JobDispatcher hold a "state" of a list of JobWorker responses that I'm waiting for, track of which ones have been received, and when I've received them all, send a response message back to the HTTP service. This is further complicated by the fact that I may have multiple simultaneous Asks coming in from the HTTP service, and I'd have to track multiple copies of this "state", and somehow identify which HTTP request each one is for.
This is all WAY more complicated than the the aggregate Future solution above.
What is the simple/correct way to handle situations like this in Akka Typed?
The docs suggest using a per-session child actor for this situation. The child actor, being only associated with a single HTTP request is implicitly tracking exactly one copy of that state and is also able to manage the state of the process of scatter/gathering jobs (e.g. around timeouts and retries).
It's also worth noting that the example classic code has a massive bug: never call sender in code involving futures. Mixing futures and actors is superficially easy but also easy to turn into something that only works by coincidence (with tests often exhibiting that coincidental behavior).

How to test an actor?

How can I test an actor? Since the calls are not synchronous, and one messages can cause multiple messages to be sent, what are the ways of testing it?
E.g. How can I test that my actor sent 3 messages in response to another message?
In general you cannot test what an actor has done unless it interacts with a trait or interface you provide in the construction or in an input message. So if you have an actor like the following.
actor MyActor
be do_stuff(receiver: MyReceiver)
You use a pattern where you combine a timer, for a timeout, and a wrapper actor that provides MyReceiver to test if the actor actually did send the message or sequence of messages that where expected.
Pony already includes the ponytest package with some support for this kind of tests. You can check the PonyTest actor at GitHub. Basically you have to specify a timeout and ensure one of your actors calls complete in the test helper for success. Note that the API has changed since the last stable version.

Does the ask pattern work with Akka IO actors?

Say I have an IO Actor connection capable of sending and receiving messages over TCP. In my actor, I ask the other side of the connection for a response:
connection.ask(ByteString("stuff")).collect {
case Received(response) => log.debug(response.utf8String)
}
It appears that with this code the ask future times out, and instead the containing actor receives the raw message outside of the ask pattern.
Can you use the ask pattern with Akka IO actors? If not, why not?
I don't know the architecture in detail, but here's how I would explain it to myself:
The problem with Akka IO connector actors here is that they don't work in a request-response manner. And if you think about it - that makes sense, because TCP is not a request-response protocol. TCP doesn't even have a notion of message. From programmer's perspective TCP connection is just a pair of continuous byte streams - one in each direction. That's it.
Akka IO is a minimal actor layer on top of network protocols, so it's not surprising that it mimics this behaviour. When TCP actor receives some data from the network, it only knows one thing - that it should send a Received message to the actor that originally sent the Connect message. That's all. It has no idea that the data it received from the network is somehow related to the data that you sent earlier.
Adding to all of that, ask pattern works only under assumption that when you send message A to some actor, it will respond with the message B by sending it exactly to the sender of message A. As we already know, TCP actor doesn't do that - it simply sends everything to the sender of original Connect message.
The reason why this assumption is required is that ask pattern actually creates some sort of a "phantom" actor that is set as the sender of the message sent using ask. This "phantom" actor will then receive the response and invoke all the callbacks registered on the Future. As a side note - be aware that those callbacks are invoked completely independently of the sending actor, i.e. they may run concurrently to it!
So, I would finally conclude that the ask pattern used like this will not work with Akka IO, because it's simply too low level for such an abstraction. If you still want it, you need to create you own layer of abstraction on top of Akka IO, e.g. some simple intermediate actor that covers TCP connector actor and implements the request-response behaviour.
As an additional reference to #ghik's answer, here's roughly how I created an intermediate actor to enable the ask pattern for IO on the rest of my actors.
class IOAskHandlerActor(address: InetSocketAddress) extends Actor {
override def receive = {
// Connection setup code omitted
case Connected(remote, local) =>
// other code omitted
context become latch(sender())
}
def latch(connection: ActorRef): Receive = {
case outgoing =>
context become receiving(connection, sender())
connection ! MySerializer.write(outgoing)
}
def receiving(connection: ActorRef, asker: ActorRef): Receive = {
case Received(incoming) =>
context become latch(connection)
asker ! MySerializer.read(incoming)
}
}
Instances of this class can be asked for responses. Note that I have only tested this with one simultaneous asker (which is my use case) and this probably doesn't work for multiple askers.

Difference between ask and tell in Akka?

Reading the Scala doc I am having difficulty understanding the difference between ask and tell.
http://doc.akka.io/docs/akka/snapshot/scala/actors.html states :
! means “fire-and-forget”, e.g. send a message asynchronously and
return immediately. Also known as tell.
? sends a message asynchronously and returns a Future representing a
possible reply. Also known as ask.
If the actor I'm using spawns a web request then what is the difference between ask and tell ? In both cases the request will be spawned asynchronously and must wait for a response, in other words how can "tell" return immediately if the actor is invoking a web service and awaiting a response ?
The difference between ask and tell is from the point of view of the message sender (which is not necessarily an actor). ask will send the message and return a future, which can be awaited until timeout or a reply is received, tell will send the message and return immediately.
In the case of ask, the actor that receives the message should reply to the sender when the operation is completed.
It sounds like you already know the basic difference between ask and tell, but don't understand how tell could be used to involve other actors in handling HTTP requests.
In order for it to make sense to use tell in your HTTP request handlers, you have to use an HTTP server that does not require that request handlers return their responses. Spray is such an HTTP server.
In Spray a request handler does not return its response; it is given a RequestContext object, and responding to the request involves invoking some method on it. You can simply send that RequestContext to another actor, which can then respond to the request:
path("foo") {
rc => rc complete "foo" // respond here
} ~
path("bar") {
rc => barActor ! DoBar(rc) // send it to bar; NO RESPONSE HERE
}
Then the actor referred to by barActor could say
case DoBar(rc) =>
rc complete "bar" // respond here, in another actor
The fact that Spray packages up the request context into an object that can be passed around and completed from any actor is a great fit for the actor model. If, on the other hand, your web framework requires that the invoked handler return the response, then if you want to involve another actor your only choice is to use ask.
Typesafe announced that Play will soon use Spray underneath. I hope that means that Play will then allow requests to be sent along to other actors for processing.

Enforce synchronicity in multi agent systems

In an effort to learn both scala and akka I'm writing a Battleship game. I've not started actually writing any code yet, I'm merely thinking about how things would work.
I have agents for ships and player fleets, and messages such as "shot fired", "hit", "miss", "all ships killed". My first stumbling block is that when player 1 shoots it creates a burst of events, and player 2 must wait until all has settled before he can play his turn. How can I make sure of that ? I thought maybe I'd always send a reply no matter what, and then count that a sender receive exactly as many answers as messages sent. Maybe Battleship isn't the best candidate application for agents.
This also brings the question of making the difference between receiving no answer because the message was not processed yet, the agent didn't reply anything, or the agent died. But I'll save that one for later.
There are a number of things you might want to do here:
Have the first actor receive replies to each of its messages and then send a your turn message to the second actor
Send a message to the second actor indicating how many events in a given turn must be received
These are achievable as follows:
import akka.pattern._
(d1 ? m1) zip (d2 ? m2) pipeTo that
in the above example, d1/2 are the destination actors, m1/2 are the messages to be sent. The replies from these actors are zipped together (into a Tuple2) and forwarded on to the second actor (that in the example)
The second mechanism is a bit more involved; I've written similar things using SyncPoints. So, something like this:
case class SyncPoint(id: UUID, participants: ActorRef*)
object SyncPoint {
def newFor(participants: ActorRef*) = SyncPoint(UUID.createRandomUUID, participants)
}
Then the creator of a message sends out a SyncPoint to the ultimate observer first
val sync = SyncPoint.newFor(d1, d2)
that ! sync
Now the ultimate receiver knows it is expecting a message on this SyncPoint for each participant.
d1 ! SyncPart(m1, sync)
d2 ! SyncPart(m2, sync)
Where
case class SyncPart(msg: Any, sync: SyncPoint)
The actors d1 and d2 will forward on to that when they have processed their part in the message.
case class SyncPartial(sync: SyncPoint, participant: ActorRef)
In this way, that knows it is expecting messages from a number of participants and can then track when these participants have performed their processing.