3
votes

I'm playing around with Actor Routing and I can't send a reply back to the router so that another actor in the routing list can pick this up. I'm using:

sender.tell([Message], context.parent)

to reply to the router as according to akka docs, routed actors set the sender to themselves and their parent is the actual router

when replying it will give the following message in the console:

[INFO] [12/13/2013 11:19:43.030] [StarBucks-akka.actor.default-dispatcher-2] [akka://StarBucks/deadLetters] Message [net.addictivesoftware.starbucks.MakeCoffee$] from Actor[akka://StarBucks/user/Melanie#-847662818] to Actor[akka://StarBucks/deadLetters] was not delivered. [1] dead letters encountered.

The main class is:

object Starbucks extends App {
  implicit val system = ActorSystem.create("StarBucks")

  val employees = List(
    system.actorOf(Props[Employee], "Penny"),
    system.actorOf(Props[Employee], "Leonard"),
    system.actorOf(Props[Employee], "Sheldon")
  )

  val customers = List(
    ("Raj", "Tall Latte Machiato"),
    ("Howard", "Double Tall Cappuccino"),
    ("Bernadette", "Grande Spicy Pumpkin Latte"),
    ("Amy", "Dopio Espresso")
  )

  val starBucks = system.actorOf(
        Props.empty.withRouter(SmallestMailboxRouter(routees=employees)))

  customers foreach { request =>
    println("Customer %s orders a %s".format(request._1, request._2))
    starBucks ! CanIHave(request._1, request._2)
  }
}

The routed actor class is:

class Employee extends Actor {
  def receive = {
    case CanIHave(coffee, name) => {
      println("Employee %s writes '%s' and '%s' on a cup".format(self.path.name, coffee, name) )
      sender.tell(MakeCoffee(coffee, name), context.parent)
    }
    case MakeCoffee(coffee, name) => {
      println("Employee %s makes a %s for %s ".format(self.path.name, coffee, name) )
      sender.tell(CoffeeReady(coffee, name), context.parent)
    }
    case CoffeeReady(coffee, name) => {
      println("Employee %s shouts: %s for %s is ready!".format(self.path, name, coffee, name))
    }
  }
}
1

1 Answers

3
votes

Your problem is that your routees are not created by the router itself but by the Akka system with :

system.actorOf(Props[Employee], "Penny")

Therefore context.parent at the employee level will return the Akka system which will redirect your messages to the dead-letters mailbox.

EDIT : According the documentation, see the section Routers, Routees and Senders which states explicitly

Note that different code would be needed if the routees were 
not children of the router, i.e. if they were provided when the router was created.

This is exactly your situation, you are building your employees actors under the system actor and then you pass the ActorRef list as an argument of to the router's constructor.