Akka Pattern - Actor tree, reply to original source - scala

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.

Related

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

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().

Is sending futures in Akka messages OK?

I'm working on implementing a small language to send tasks to execution and control execution flow. After the sending a task to my system, the user gets a future (on which it can call a blocking get() or flatMap() ). My question is: is it OK to send futures in Akka messages?
Example: actor A sends a message Response to actor B and Response contains a future among its fields. Then at some point A will fulfill the promise from which the future was created. After receiving the Response, B can call flatMap() or get() at any time.
I'm asking because Akka messages should be immutable and work even if actors are on different JVMs. I don't see how my example above can work if actors A and B are on different JVMs. Also, are there any problems with my example even if actors are on same JVM?
Something similar is done in the accepted answer in this stackoverflow question. Will this work if actors are on different JVMs?
Without remoting it's possible, but still not advisable. With remoting in play it won't work at all.
If your goal is to have an API that returns Futures, but uses actors as the plumbing underneath, one approach could be that the API creates its own actor internally that it asks, and then returns the future from that ask to the caller. The actor spawned by the API call is guaranteed to be local to the API instance and can communicate with the rest of the actor system via the regular tell/receive mechanism, so that there are no Futures sent as messages.
class MyTaskAPI(actorFactory: ActorRefFactory) {
def doSomething(...): Future[SomethingResult] = {
val taskActor = actorFactory.actorOf(Props[MyTaskActor])
taskActor ? DoSomething(...).mapTo[SomethingResult]
}
}
where MyTaskActor receives the DoSomething, captures the sender, sends out the request for task processince and likely becomes a receiving state for SomethingResult which finally responds to the captured sender and stops itself. This approach creates two actors per request, one explicitly, the MyTaskActor and one implicitly, the handler of the ask, but keeps all state inside of actors.
Alternately, you could use the ActorDSL to create just one actor inline of doSomething and use a captured Promise for completion instead of using ask:
class MyTaskAPI(system: System) {
def doSomething(...): Future[SomethingResult] = {
val p = Promise[SomethingResult]()
val tmpActor = actor(new Act {
become {
case msg:SomethingResult =>
p.success(msg)
self.stop()
}
}
system.actorSelection("user/TaskHandler").tell(DoSomething(...), tmpActor)
p.future
}
}
This approach is a bit off the top of my head and it does use a shared value between the API and the temp actor, which some might consider a smell, but should give an idea how to implement your workflow.
If you're asking if it's possible, then yes, it's possible. Remote actors are basically interprocess communication. If you set everything up on both machines to a state where both can properly handle the future, then it should be good. You don't give any working example so I can't really delve deeper into it.

Akka actors returning different types of output

I have a project that is using Akka Actors in scala, and I'm running into some issues regarding the actors that do processing and send the results back to the sender.
To better explain, here is the workflow that my project has
Commander send msg to Poller
Poller sends SuccessMessage(self, List[String]) to Commander
Commander sends List[String] to Processor
Processor sends SuccessMessage(self, File) to Commander
Commander sends File to Uploader
Uploader sends SuccessMessage(self, Boolean) to Commander
and so on.
Essentially, I have two questions:
Right now, I wrap everything that is returned from an actor back to the Commander (supervisor) in a SuccessMessage. Is this the best way of doing it, or is there another way to handle many different types of return?
The SuccessMessage will also have a "payload". I am debating between using generics for the payload type, or just making it an Option[Any] and then doing a lot of casting on the commander side, before sending it to any actor (poller, processor, etc.). I know that in Java akka actors just cast Object; would I have to do the same?
There is no "right" way, but I this is how I would do it:
Make messages unique to each actor type pair. Wrap the actual data in these messages: Poll(something), Polled(result), Process(something), Processed(result), Upload(something) and Uploaded(result).
Then either make PollFailed(details), ProcessingFailed(details) and UploadFailed(details) messages or put Option in the normal result messages. I like using Option.
I'd define these messages in the Poller's, Processer's and Uploader's companion objects.
The commander's receive method is then quite pretty:
def receive = {
case Polled(Some(result)) => // handle
case Polled(None) => // handle
case Processed(Some(result)) => // handle
case Processed(None) => // handle
case Uploaded(Some(result)) => // handle
case Uploaded(None) => // handle
}
Stay away from generics. Thanks to type erasure you cannot match generics in the receive method.
I haven't seen your code, but I would suggest doing two things:
Create different types of messages for success. E.g.
MessagesPolled(List[String]),
MessagesProcessed(File)
MessagesUploaded and MessagesNotUploaded(Error)
This way your logic will be divided in proper and logic connected to each message will be held in different place (and later on can be changed without affecting other logics).
Create hierarchy of actors so that each of them is responsible for one thing (including the top actor), e.g.:
Commander has references to three actors (which have their own worker hierarchies):
Poller which only routes messages to dynamically created PollerWorkers
Processor which only routes messages to dynamically created ProcessorWorkers
Uploader which only routes messages to dynamically created UploaderWorkers
Commander receives a trigger message and sends first message to Poller with a ActorRef to the nextStepActor which, in the case of first message, will be ProcessorWorker
This way you will be able to encapsulate logic in different actors, scale easily and not overwhelm the Commander 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.

Nested react (or receive) in Scala

I have an intermediate remote actor (B) that is supposed forward back and forth messages from A and C ( like A <-> B <-> C ). In B's code I have something like
loop {
react {
case msg => val A = sender
//2) Should this be synchronous with !?
C ! msg
//1) What's better react or receive?
react {
case response => A ! response
}
}
}
3 Questions:
1) What's better react or receive (to nest within a react)?
2) Given that a response will be sent back, should !? be used instead of !
3) Any other recommendation for this scenario?
Thank you all!
For what concerns the standard Actor model, messages must be handled atomically (i.e. you cannot receive and process messages when you are processing another -- and that's exactly what you'd like to do here)
However, Scala Actors have a relaxed semantics, which may allow to do that.
For Question 1, you should have clear which are the differences between react and receive. Anyway, you can easily use react (as used here http://www.scala-lang.org/docu/files/actors-api/actors_api_guide.html)
Alternatively, you could not use nesting. After your actor has sent the request, its state should change so that that next loop cycle it will look for the reply.
You may also want to upgrade to Scala 2.10 which integrate actors from Akka; that model is more clear and easy to use.