Life cycle of an actor

Our implementation of the Mixer is quite naive and does not take into account that hardware occasionally breaks.

Conventionally, in Akka, we distinguish between expected and unexpected failures. An expected failure of some operation, for example, a validation error is usually represented on the protocol level with the appropriate message types. Exceptional conditions of an unexpected nature such as hardware errors, are communicated by throwing exceptions. This allows you to separate handler definitions for successful and erroneous paths, which leads to the separation of business logic from the technical details of the underlying platform. Thus, having a rich set of exceptions is a prerequisite for proper error-handling definitions.

Let's take this aspect into account. We'll represent unreliable hardware by defining a set of exceptions, one for every possible failure. We'll do this the same way as we did in Chapter 11, An Introduction to the Actor Model and Akka:

class MotorOverheatException extends Exception
class SlowRotationSpeedException extends Exception
class StrongVibrationException extends Exception

Now, in order to simulate the hardware failure, we'll add some code with the purpose of throwing defined exceptions to the logic of the Mixer. To keep the example simple, let's just throw one of them:

case (_, Mix(Groceries(eggs, flour, sugar, chocolate), sender)) =>
if (Random.nextBoolean()) throw new MotorOverheatException
...

It looks like it is very warm in our bakery. The mixer motors are overheating roughly every second time the Chef tries to mix the Groceries.

Actors can watch themselves by calling the receiveSignal method on the actor's context and providing a PartialFunction[(ActorContext[T], Signal), Behavior[T]] as a parameter. The provided partial function will be called, with a life cycle message as a parameter, if the actor terminates or restarts.

This possibility for self-watching can be useful to change the behavior of the actor in appropriate cases. The following code snippet shows how mixers can monitor themselves:

val monitoring: PartialFunction[(ActorContext[Mix], Signal), Behavior[Mix]] = {
case (ctx, PostStop) =>
ctx.log.info("PostStop {}", context.self)
Behaviors.same
case (context, PreRestart) =>
ctx.log.info("PreRestart {}", context.self)
Behaviors.same
case (context, t: Terminated) =>
ctx.log.info("Terminated {} while {}", context.self, t.failure)
Behaviors.same
}

In our case, mixers just write into the log what kind of life-changing event had happened and keep the same behavior. To take a look at the situations in which PostStop, PreRestart, and Terminated events happen, we first need to become familiar with the concept of supervision.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.135.213.212