Creating an actor

In accordance to the actor model definition, there is exactly one way that an actor can be created—it can be spawned by another actor. Akka gives you two slightly different possibilities to do this by using ActorContext. Both methods are not thread safe and should only be used directly within the actor's thread.

The first variant allows you to instantiate an anonymous actor from a behavior and returns an ActorRef[T]:

def spawnAnonymous[T](behavior: Behavior[T], props: Props = Props.empty): ActorRef[T]

This implementation provides a default empty value for the props parameter so that the actual call can be reduced to spawnAnonymous(behavior).

Not naming actors might be useful in specific situations, but it is considered to be a bad practice in general. This is because it makes debugging harder and looking up children by name impossible without relying on the current implementation details of the library.

Thus, another realization should be preferred whenever it makes sense to use one: 

def spawn[T](behavior: Behavior[T], name: String, props: Props = Props.empty): ActorRef[T]

Here, we're required to provide a behavior and a name for an actor, which is about to be instantiated.

Both spawn and spawnAnonymous accept a props parameter, which can be used to further configure an actor instance. As of now, it is only possible to configure an actor's dispatcher.

Dispatchers make up the machinery that runs behaviors. Dispatchers use ExecutorServices to assign threads to actors and can be configured as described in Chapter 11, An Introduction to the Akka and Actor Models. Currently, Akka Typed only supports the dispatchers definition from the configuration. Properties of the default dispatcher can be changed by overriding the settings under akka.actor.default-dispatcher .

In our example system, the Chef actor should instantiate Mixers as being required to work with big chunks of work in parallel. In addition, mixers use blocking code because of the limitations of hardware and therefore need separate dispatchers in order to avoid thread starvation for the rest of the system. Let's look at how this behavior can be implemented.

First, by using application.conf, we configure a dispatcher that will be used for blocking mixers:

mixers-dispatcher {
executor = "thread-pool-executor"
type = PinnedDispatcher
}

Then, we instantiate the required number of child actors:

object Chef {
sealed trait Command
final case class Mix(g: Groceries, manager: ActorRef[Manager.Command]) extends Command
def idle = Behaviors.receive[Command] {
case (context, mix@Mix(Groceries(eggs, flour, sugar, chocolate), manager)) =>
val props = DispatcherSelector.fromConfig("mixers-dispatcher")
val mixers = for (i <- 1 to eggs) yield
context.spawn(Mixer.mix, s"Mixer_$i", props)
mixing
}
def mixing = Behaviors.unhandled[Command]i
}

The Chef actor has its own hierarchy of commands which we, for now, limit to Mix. We need a separate Mixer for each egg, so we instantiate them by using spawnspawn returns an actor reference and we collect them in the mixers val. Finally, we return the next actor's Behavior, which for now is unhandled.

OK, so it's possible to create new actors from an actor's context. This brings us to a Zeno's paradox kind of situation with Achilles and the tortoise. Naturally, to create a new actor, we need to have an actor already. Akka solves this paradox by requiring the developer to provide a definition of a root actor at the moment an actor system is created:

def apply[T](guardian: Behavior[T],name: String): ActorSystem[T]

This leaves the developer with no choice but to design a proper actor hierarchy top-down. Following this typed approach automatically leads to avoidance of the flat actor hierarchy anti-pattern!

There is another possibility for instantiating an actor. This can be done by using the ActorSystem's systemActorOf method, which creates an actor in the /system space. It is arguable that this feature shouldn't normally be used, and therefore it is not covered here.

Now, since our Chef spawned enough Mixers to do the job, we need a way to get rid of them after our work is complete.

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

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