Kotlin + Akka Part 3: Dispatchers
The Akka Dispatcher defines the wiring of an Actor within an Actor System, such as how the Actor’s mailbox is configured and what implementation of the java.util.concurrent.ExecutorService to use.
The default dispatcher for an Actor System creates one mailbox per actor and is backed by the fork-join-executor (which makes use of a slightly modified version of Java’s ForkJoinPool).
Let’s start off with a simple example using the default dispatcher for an Actor System:
Which produces the following output:
[INFO] [04/29/2018 14:08:06.206] [part3-akka.actor.default-dispatcher-3] [akka://part3/user/actor1] Hello Actor 1
[INFO] [04/29/2018 14:08:06.206] [part3-akka.actor.default-dispatcher-2] [akka://part3/user/actor2] Hello Actor 2
The Default Dispatcher, whose name is displayed in the log output, provides both threads used by the Actors.
Akka provides a number of out-the-box Dispatchers that can be configured in a number of ways, each with their own characteristics:
Dispatcher (default) — One mailbox per Actor, backed by a thread pool, and can be shared across multiple actors. Since the thread pool is shared, this is recommended for non-blocking actors that perform short lived tasks.
Pinned Dispatcher — One mailbox per Actor, backed by a single threaded pool, and cannot be shared across actors (ie the Actor is assigned it’s own thread). Useful for Actors that perform long running, blocking tasks (such as Database Calls).
CallingThreadDispatcher — One mailbox per Actor per Thread and does not create any new threads. In other words, the thread that sends a message to an actor is also used to deliver and process the message. This is useful for testing to create deterministic behaviour.
Akka allows us to configure the Dispatcher in a few different ways; we can define the Dispatcher and configure it programmatically, or we can use the deployment configuration.
From the previous example, let’s define Actor 1 with a Custom Dispatcher with pure configuration, and Actor 2 with a Pinned Dispatcher programmatically:
First we setup our Akka configuration file to define our different dispatchers:
And then we update our previous code to load our new configuration and explicitly set the dispatcher for Actor 2:
And after running the code we get:
[INFO] [04/29/2018 14:56:05.817] [part3-actor1-dispatcher-5] [akka://part3/user/actor1] Hello Actor 1
[INFO] [04/29/2018 14:56:05.817] [part3-actor2-dispatcher-6] [akka://part3/user/actor2] Hello Actor 2
Which now displays the names of our custom dispatcher configuration.
This incredibly flexible Dispatcher system allows us to easily apply Bulkheading (fancy word for segregating parts of an application, like a ship’s hull, to minimize the impact of a single part failing) in the sense that blocking Actors do not need to hold up the threads from non-blocking actors.
We have briefly looked into how Dispatchers are used within Akka and different ways to configure them for an Actor System. It’s important to consider which category of tasks each Actor does and set up the Dispatchers accordingly.
In the next section, we will look at how scheduling is handled in Akka.