Search code examples
scaladesign-patternsakkamessage-passingakka-cluster

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!


Solution

  • 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);