Reputation: 2939
I have followed this tutorial: http://doc.akka.io/docs/akka/2.0/intro/getting-started-first-scala.html
Basically there is a Master actor which responds to these two messages:
def receive = {
case Calculate => {
//....
}
case Result(value) => {
//....
}
}
We send the message "Calculate" and after several "Result"s (from the slave actors) we have the correct calculation
Now I am inside an action of a play2 controller and I am using this:
val promise = (master ? Calculate)(10.seconds).mapTo[String].asPromise
Unfortunately (obviously) I get nothing because Calculate message does reply with a message to the sender.
I would like to somehow make the Akka Actor wait.... and when the computation is complete to send a message back to the sender.
But how?... Unless I am modelling it in the wrong way!
Upvotes: 3
Views: 4419
Reputation: 24040
You should either forward
the message to the slaves (which keeps the same sender), or include the sender in the message to the slaves. For example:
def receive = {
case Calculate => slave ! CalculateWithSender(sender)
case res @ Result(value, originalSender) =>
val result = resultMap(originalSender) + res // assuming results are just added
resultMap += (originalSender -> result)
if (resultsAreFinished(originalSender))
originalSender ! result
}
or
def receive = {
case Calculate => slave.forward(Calculate)
case res @ Result(value, originalSender) =>
val result = resultMap(originalSender) + res // assuming results are just added
resultMap += (originalSender -> result)
if (resultsAreFinished(originalSender))
originalSender ! result
}
or
def receive = {
case Calculate => slave.tell(Calculate, sender)
case res @ Result(value, originalSender) =>
val result = resultMap(originalSender) + res // assuming results are just added
resultMap += (originalSender -> result)
if (resultsAreFinished(originalSender))
originalSender ! result
}
I'm not familiar with Play promises, but ?
(ask
) returns a Akka Future
. If .asPromise
converts an Akka Future
to a Play Promise
then you're set.
Upvotes: 4
Reputation: 11366
Spin up a new actor for each calculation. forward the Calculate message to the new actor. The new actor stores the original sender. When the result is ready, the result is sent to the original sender, and the ephemeral actor dies:
class CalculateActor extends Actor {
var origSender : ActorRef = _
def receive {
case Calculate => {
origSender = sender
slaveActors ! doStuff
//....
}
case Result(value) => {
if(results are ready) {
origSender ! results
self ! PoisonPill // I'm done, time to die
}
}
}
class MasterActor extends Actor {
def receive {
case msg @ Calculate => {
// forward sends without changing the sender
context.actorOf(Props(new CalculateActor)).forward(msg)
}
}
}
Upvotes: 1