Actors in Akka define a number of methods which are called at different moments during their lifetime, specifically:
- preStart: Called after the actor is started or during restart
- preRestart: Called on the actor which is about to be destroyed because of the restart
- postRestart: Called on the actor who was just created after the restart
- postStop: Called after the actor is stopped
The order of execution, given two instances of the same actor—one that has failed and another one that has been created as a replacement—is shown as follows:
- Actor A, stopping: constructor | preStart | preRestart | postStop
- Actor B, starting: constructor | postRestart | preStart | postStop
Now, we can implement a Chef actor.
This actor will combine ingredients to produce dough. It will use its magical powers to create a Mixer and will use this Mixer to do the actual blending work. One Mixer has limited capacity, and so the Chef will need to create multiple mixers for bigger shopping lists and use them in parallel in order to speed up the preparation process.
We'll start by defining a mixer:
object Mixer {
final case class Groceries(eggs: Int, flour: Int, sugar: Int, chocolate: Int)
def props: Props = Props[Mixer].withDispatcher("mixers-dispatcher")
}
class Mixer extends Actor {
override def receive: Receive = {
case Groceries(eggs, flour, sugar, chocolate) =>
Thread.sleep(3000)
sender() ! Dough(eggs * 50 + flour + sugar + chocolate)
}
}
The Mixer only understands a single type of message, Groceries. After getting this type of message, it produces a certain amount of Dough by mixing all of the ingredients together and returns it to the sender. Thread.sleep represents blocking—waiting for the hardware to complete its operation.
Unfortunately, in our case, blocking is unavoidable during the mixing operation because of hardware limitations. Akka offers a solution to this problem in the form of dispatchers.