Use forward
, which preserves the original sender when passing messages between actors.
In this case, you don't even need to send the return data via Actor2
class Actor2 extends Actor {
def receive = {
case Actor2Request =>
val actor3 = context actorOf (Props[Actor3])
//sender will still be actor1 when actor3 receives this forwarded message
actor3 forward Actor3Request
}
}
class Actor3 extends Actor {
def receive = {
case Actor3Request =>
//doing some work...
sender ! data // sender is actor1
}
}
If you do need to return via Actor2
, perhaps for some intermediate processing, then you want to capture the original sender and pass it via the actor messages:
class Actor2 extends Actor {
def receive = {
case Actor2Request =>
val actor3 = context actorOf (Props[Actor3])
//sender at this point is actor1
actor3 ! Actor3Request(sender)
case DoneActor3(origin, data) =>
// Do some other stuff here
origin ! data //origin is the original sender as passed to Actor3Request
}
}
class Actor3 extends Actor {
def receive = {
case Actor3Request(origin) =>
//doing some work...
sender ! DoneActor3(origin, data) // origin is actor1, sender is actor2
}
}
Or you can mix & match the techniques, having Actor3
send a message direct to origin
UPDATE
There's one final solution, which is valid here because actor2
was created by actor1
. In this case we know that actor1
will be the parent of actor2
in the supervision hierarchy:
class Actor2 extends Actor {
def receive = {
case Actor2Request =>
val actor3 = context actorOf (Props[Actor3])
actor3 ! Actor3Request
case DoneActor3(data) =>
// Do some other stuff here
context.parent ! data //context.parent is actor1
}
}
class Actor3 extends Actor {
def receive = {
case Actor3Request =>
//doing some work...
sender ! DoneActor3(data) //sender is actor2
}
}