Akka Classic Ask pattern. How does it match asks with responses? - scala

I'm a newbie with Akka Actors, and I am learning about the Ask pattern. I am looking at the following example from alvin alexander:
class TestActor extends Actor {
def receive = {
case AskNameMessage => // respond to the "ask" request
sender ! "Fred"
case _ => println("that was unexpected")
}
}
...
val myActor = system.actorOf(Props[TestActor], name = "myActor")
// (1) this is one way to "ask" another actor
implicit val timeout = Timeout(5 seconds)
val future = myActor ? AskNameMessage
val result = Await.result(future, timeout.duration).asInstanceOf[String]
println(result)
(Yes, I know that Await.result isn't generally the best practice, but this is just a simple example.)
So from what I can tell, the only thing you need to do to implement the "askee" actor to service an Ask operation is to send a message back to the "asker" via the Tell operator, and that will be turned into a future on the "asker" side as a response to the Ask. Seems simple enough.
My question is this:
When the response comes back, how does Akka know that this particular message is the response to a certain Ask message?
In the example above, the "Fred" message doesn't contain any specific routing information that specifies that it's the response to a particular Ask operation. Does it just assume that the next message that the asker receives from that askee is the answer to the Ask? If that's the case, then what if one actor sends multiple Ask operations to the same askee? Wouldn't the responses likely get jumbled, causing random responses to be mapped to the wrong Asks?
Or, what if the asker is also receiving other types of messages from the same askee actor that are unrelated to these Ask messages? Couldn't the Asks receive response messages of the wrong type?
Just to be clear, I'm asking about Akka Classic, not Typed.

For every Ask message sent to an actor, akka creates a proxy ActorRef whose sole responsibility is to process one single message. This temp "actor" is initialized with a promise, which it needs to complete on message processing.
The source code of it is found here
but the main details are
private[akka] final class PromiseActorRef private (
val provider: ActorRefProvider,
val result: Promise[Any],
....
val alreadyCompleted = !result.tryComplete(promiseResult)
Now, it should be clear that Ask pattern is backed by independent unique actor asker for every message sent to the receiver askee.
The askee does know actor reference of the sender, or asker, of every message received via method context.sender(). Thus, it just needs to use this ActorRef to send a response back to the asker.
Finally, this all avoids any race conditions given that an actor only processes a message at a time. Thus it excludes any possibility of retrieving a "wrong" asker via method context.sender().

Related

Chaining Akka Actors in a Spray Route

I have a restful API that receives an array of JSON messages that will be converted to individual Avro messages and then sent to Kafka. Inside the route, I call 3 different actors: 1) one actor goes out and retrieves the Avro schema from disk 2) then loop through the array of JSON messages and compare it to the Avro schema in a second actor. If any of the messages don't validate, then I need to return a response back to the caller of the API and stop processing. 3) Loop through the array and pass into a 3rd actor that takes the JSON object, converts it to an Avro message and sends to a Kafka topic.
Where I'm having problem getting my head wrapped around is how to stop processing in the route if something fails in one of the actors. I'm passing in the request context to each actor and calling it's complete method but it doesn't seem to immediately stop, the next actor still processes even when it shouldn't. Here is a code snippet of what I'm doing in the route:
post {
entity(as[JsObject]) { membersObj =>
requestContext =>
val membersJson = membersObj.fields("messages").convertTo[JsArray].elements
val messageService = actorRefFactory.actorOf(Props(new MessageProcessingServicev2()))
val avroService = actorRefFactory.actorOf(Props(new AvroSchemaService()))
val validationService = actorRefFactory.actorOf(Props(new JSONMessageValidationService()))
implicit val timeout = Timeout(5 seconds)
val future = avroService ? AvroSchema.MemberSchema(requestContext)
val memberSchema:Schema = Await.result(future, timeout.duration).asInstanceOf[Schema]
for (member <- membersJson) validationService ! ValidationService.MemberValidation(member.asJsObject, memberSchema, requestContext)
for (member <- membersJson) (messageService ! MessageProcessingv2.ProcessMember(member.asJsObject, topicName, memberSchema, requestContext))
I've looked through a lot of blogs/books/slides around this topic and not sure what the best approach is. I've been using Scala/Akka for about 2 months and basically self taught on just the pieces that I've been needing. So any insight that the more seasoned Scala/Akka/Spray developers have in this, it's much appreciated. The one thought I had was to wrapper the 3 actors in a 'master' actor and make each a child of that actor and attempt to approach it like that.
As you are using async processing (!) you cannot control the processing after your messages have been sent. You would need to use ask (?) that will return a future you can work with.
But I have a better idea. You could send a message from the first actor to the second. And instead of returning a result to the first actor, you could send the message to the third one to keep on the computation.

How can I gather state information from a set of actors using only the actorSystem?

I'm creating an actor system, which has a list of actors representing some kind of session state.
These session are created by a factory actor (which might, in the future, get replaced by a router, if performance requires that - this should be transparent to the rest of the system, however).
Now I want to implement an operation where I get some state information from each of my currently existing session actors.
I have no explicit session list, as I want to rely on the actor system "owning" the sessions. I tried to use the actor system to look up the current session actors. The problem is that I did not find a "get all actor refs with this naming pattern" method. I tried to use the "/" operator on the system, followed by resolveOne - but got lost in a maze of future types.
The basic idea I had was:
- Send a message to all current session actors (as given to my by my ActorSystem).
- Wait for a response from them (preferably by using just the "ask" pattern - the method calling this broadcaster request/response is just a monitoring resp. debugging method, so blocking is no probleme here.
- And then collect the responses into a result.
After a death match against Scala's type system I had to give up for now.
Is there really no way of doing something like this?
If I understand the question correctly, then I can offer up a couple of ways you can accomplish this (though there are certainly others).
Option 1
In this approach, there will be an actor that is responsible for waking up periodically and sending a request to all session actors to get their current stats. That actor will use ActorSelection with a wildcard to accomplish that goal. A rough outline if the code for this approach is as follows:
case class SessionStats(foo:Int, bar:Int)
case object GetSessionStats
class SessionActor extends Actor{
def receive = {
case GetSessionStats =>
println(s"${self.path} received a request to get stats")
sender ! SessionStats(1, 2)
}
}
case object GatherStats
class SessionStatsGatherer extends Actor{
context.system.scheduler.schedule(5 seconds, 5 seconds, self, GatherStats)(context.dispatcher)
def receive = {
case GatherStats =>
println("Waking up to gether stats")
val sel = context.system.actorSelection("/user/session*")
sel ! GetSessionStats
case SessionStats(f, b) =>
println(s"got session stats from ${sender.path}, values are $f and $b")
}
}
Then you could test this code with the following:
val system = ActorSystem("test")
system.actorOf(Props[SessionActor], "session-1")
system.actorOf(Props[SessionActor], "session-2")
system.actorOf(Props[SessionStatsGatherer])
Thread.sleep(10000)
system.actorOf(Props[SessionActor], "session-3")
So with this approach, as long as we use a naming convention, we can use an actor selection with a wildcard to always find all of the session actors even though they are constantly coming (starting) and going (stopping).
Option 2
A somewhat similar approach, but in this one, we use a centralized actor to spawn the session actors and act as a supervisor to them. This central actor also contains the logic to periodically poll for stats, but since it's the parent, it does not need an ActorSelection and can instead just use its children list. That would look like this:
case object SpawnSession
class SessionsManager extends Actor{
context.system.scheduler.schedule(5 seconds, 5 seconds, self, GatherStats)(context.dispatcher)
var sessionCount = 1
def receive = {
case SpawnSession =>
val session = context.actorOf(Props[SessionActor], s"session-$sessionCount")
println(s"Spawned session: ${session.path}")
sessionCount += 1
sender ! session
case GatherStats =>
println("Waking up to get session stats")
context.children foreach (_ ! GetSessionStats)
case SessionStats(f, b) =>
println(s"got session stats from ${sender.path}, values are $f and $b")
}
}
And could be tested as follows:
val system = ActorSystem("test")
val manager = system.actorOf(Props[SessionsManager], "manager")
manager ! SpawnSession
manager ! SpawnSession
Thread.sleep(10000)
manager ! SpawnSession
Now, these examples are extremely trivialized, but hopefully they paint a picture for how you could go about solving this issue with either ActorSelection or a management/supervision dynamic. And a bonus is that ask is not needed in either and also no blocking.
There have been many additional changes in this project, so my answer/comments have been delayed quite a bit :-/
First, the session stats gathering should not be periodical, but on request. My original idea was to "mis-use" the actor system as my map of all existing session actors, so that I would not need a supervisor actor knowing all sessions.
This goal has shown to be elusive - session actors depend on shared state, so the session creator must watch sessions anyways.
This makes Option 2 the obvious answer here - the session creator has to watch all children anyways.
The most vexing hurdle with option 1 was "how to determine when all (current) answers are there" - I wanted the statistics request to take a snapshot of all currently existing actor names, query them, ignore failures (if a session dies before it can be queried, it can be ignored here) - the statistics request is only a debugging tool, i.e. something like a "best effort".
The actor selection api tangled me up in a thicket of futures (I am a Scala/Akka newbie), so I gave up on this route.
Option 2 is therefore better suited to my needs.

Akka Pattern - Actor tree, reply to original source

This is a design question;
Say I have a tree of actors which do a bunch of processing. The processing is kicked off by a client/connection actor (i.e. the tree is the server). Eventually the client actor wants a response. I.e. I have an actor system that looks like this.
ActorA <---reqData--- Client_Actor
| msgA /|\
\|/ |
ActorB |
msgB | \ msgD |
\|/ \/ |
ActorC ActorD---------msgY-->|
|_____________msgX_________|
The response that the client system wants is the output from the leaf actors (i.e. ActorC and/or ActorD). These actors in the tree may be interacting with external systems. This tree may be a set of pre-defined possibly routed actors (i.e. so Client_actor just has a actorref to the root of the actor tree, ActorA).
The question is what is the best pattern to manage sending the response (msgX &/or msgY) from the final/leaf actors back to the client actor?
I can think of the following options;
Create a tree for each connection client and get the actors to keep track of the sender, when they get a msgX or msgY, send it back to the original sender ref so the messages are passed back up through the tree. I.e each actor will keep a ref of the original sender.
Somehow send down the Client_Actor ref in the reqData message and replicate this for all messages used in the tree so the leaf actors can reply directly to the Client_actor... This seems like the most performant option. Not sure how to do this (I'm thinking a trait somehow on the message case classes that holds the client actor ref)...
Somehow lookup the client actor based on a unique id in the messages passed through the tree or use the actorselection (not sure how well this would work with remoting)...
Something better...
FYI I'm using Akka 2.2.1.
Cheers!
You could use the forward method to forward the message from the original sender to the child sender at each level.
in Client_Actor:
actorA ! "hello"
in ActorA:
def receive = {
case msg =>
???
actorB forward msg
}
in ActorB:
def receive = {
case msg =>
???
actorC forward msg
}
in ActorC:
def receive = {
case msg =>
???
sender ! "reply" // sender is Client_Actor!
}
In this case, the 'sender' field of the message will never change, so ActorC will reply to the original Client_Actor!
You can extend this further by using the tell method variant that lets you specify the sender:
destinationActor.tell("my message", someSenderActor);
The simpliest way is to sending messages with the ref to the source Client_Actor
Client
sendMsg(Client to, Client resultTo)
Client_Actor
req_data(Client to){
sendMsg(to, this);
}
This is good option, if you dont know, which Client has the result for the original poster and which is not.
If you know this and the Client_Actor is only one (like we have a tree and these and only LEAFS will always response to and only Client_Actor), you can do something like this :
Client
register_actor(Client actor){this.actor = actor;}
call_actor(){ this.actor.sendMsg(); }
For situations like this, I wrote something called a ResponseAggregator. It is an Actor instantiated as needed (rather than as a persistent single instance) taking as arguments a destination ActorRef, an arbitrary key (to distinguish the aggregator if a single destination gets fed by more than one aggregator), a completion predicate that takes a Seq[Any] holding responses received by the aggregator so far and which returns true if those responses represent completion of the aggregation process and a timeout value. The aggregator accepts and collects incoming messages until the predicate returns true or the timeout expires. Once aggregation is complete (including due to timeout) all the messages that have been received are sent to the destination along with a flag indicating whether or not aggregation timed out.
The code is a bit too big to include here and is not open source.
For this to work, the messages propagating through the system must bear ActorRefs indicating to whom a response message is to be sent (I rarely design actors that reply only to sender).
I often define the replyTo field of a message value as ActorRef* and then use my MulticastActor class, which enables the !* "send to multiple recipients" operator. This has the advantage of syntactic cleanliness in the message construction (by comparison to using Option[ActorRef] or Seq[ActorRef]) and has equal overhead (requiring the construction of something to capture the reply-to actor ref or refs).
Anyway, with these things, you can set up pretty flexible routing topologies.

Akka: What happens when you tell an ActorRef and it expects you to ask?

I have the following:
val future = myActor ? Message
And in my actor my receive message has something like this:
sender ! Response
If I do the following and ignore the response, is there any negative impact?
myActor ! Message
Maybe I'm just missing where it says this in the documentation. Is it like a method that returns a value and the caller doesn't assign the return value to anything? If I make that call from another actor is there going to be some weird threading issue or memory leaks that result from it? My unit tests don't seem to be affected but it's kind of a contrived. I'm hoping I'm just over-thinking the problem and maybe I can't find the answer because it's a stupid question that no one in their right mind asks.
With ask pattern Response is received by temporary light-weight actor (PromiseActorRef).
In case of myActor ! Message there should be implicit ActorRef in scope. Response will be sent to this implicit ActorRef. This message will not be garbage-collected until you explicitly read it.
If there is no implicit ActorRef in scope Actor.noSender is used and Response will be forwarded to system's deadLetters.
If you make that call from another actor this Response will be delivered to message box of this another actor.

actor:possible to send and receive nested in a receive

When process a message, is it possible to send out an message to another actor and wait for that actor to reply, and consume the replied message and then continue, like the following, is it doable?
val lineMap=HashMap[String,Int]()
receive {
case bigTaskMap=>
for (line <-readSomeFile){
if(lineMap.get(line)==None){
anotherActor!line // that actor will reply a hashmap which contain the key for line
receive {
case x:HashMap => lineMap=x
}
}
lineMap.get(line) // use that value to do further work
}
}
This answer is for Akka (old Scala actors are deprecated in Scala 2.10).
Yes. You can use ask to get a future (rather than creating a fully-fledged actor yourself) and then call onComplete on the Future returned to set an action which will be executed when the Future's value (or an error) becomes available. Don't worry about how quickly the Future might yield a value - it doesn't matter, because the onComplete action will be executed even if the Future is already available when onComplete is called!
However, be very careful: you should not directly access any of the state (i.e. the variables) in the containing actor in your action(s), because the onComplete action(s) will not run in the same execution context as the actor (i.e. they could be running at the same time as the original actor is processing a message). Instead, send further messages back to the original actor, or forward them on.
In fact, in some cases you may find the simplest thing to do is simply to send a message, and let the original actor handle the reply. become and unbecome may help here. However, again, be careful if using become, that in the actor's new behaviour, it doesn't drop "ordinary" messages that should be handled in the ordinary way.