4
votes

I'm started to learn Akka and in many official examples I see that request-response implemented using tell pattern. I.e. after worker made his work he sends result as new message back to sender. For example in this Pi approximation official tutorial shown how to design application where Master sends some work to workers and then awaits for results as another message.

Master code:

def receive = {
  case Calculate ⇒
    for (i ← 0 until nrOfMessages) workerRouter ! Work(i * nrOfElements, nrOfElements)
  case Result(value) ⇒
    pi += value
    nrOfResults += 1
    if (nrOfResults == nrOfMessages) {
      // Send the result to the listener
      listener ! PiApproximation(pi, duration = (System.currentTimeMillis - start).millis)
      // Stops this actor and all its supervised children
      context.stop(self)
    }
}

Worker code:

 def receive = {
    case Work(start, nrOfElements) ⇒
      sender ! Result(calculatePiFor(start, nrOfElements)) // perform the work
  }

But I'm wondering why this example didn't use ask pattern? What is wrong with using ask pattern here?

If it's ok to use ask pattern here, then I have another question: how I can stop all worker actors after work is done?

  1. Should my worker actors send PoisonPill message to themselves?
  2. Or should Master actor Broadcast(PoisonPill)?
  3. Or there some another more elegant way?
1

1 Answers

7
votes

ask is useful when integrating actors with Future APIs, but they do introduce some overhead. Further, Future completions do not come through an actor's mailbox and are scheduled on a thread separate from the one used by the mailbox, meaning that receiving a future completion inside an actor introduces the need for doing multi-thread coordination.

Meanwhile, if you use tell to send to a worker and have it tell the sender in response, the communication will always flow properly through the mailbox channel.

Additionally, it is much easier to discern the inputs an actor deals with if they all come in via receive rather than some coming in via receive and other's as completions of ask messages.

To address you PoisonPill questions, the answer is likely depends. You might opt for a worker-per-message approach in which case the worker should kill itself. If instead you use a worker pool, you could make the supervisor responsible for scaling that pool up and down, having it send the PoisonPill or have workers time out on idleness, once again killing themselves.