Mailboxes
An Akka Mailbox
holds the messages that are destined for an Actor
.
Normally each Actor
has its own mailbox, but with for example a BalancingPool
all routees will share a single mailbox instance.
Mailbox Selection
Requiring a Message Queue Type for an Actor
It is possible to require a certain type of message queue for a certain type of actor
by having that actor extend the parameterized trait RequiresMessageQueue
. Here is
an example:
import akka.dispatch.RequiresMessageQueue
import akka.dispatch.BoundedMessageQueueSemantics
class MyBoundedActor extends MyActor
with RequiresMessageQueue[BoundedMessageQueueSemantics]
The type parameter to the RequiresMessageQueue
trait needs to be mapped to a mailbox in
configuration like this:
bounded-mailbox {
mailbox-type = "akka.dispatch.BoundedMailbox"
mailbox-capacity = 1000
mailbox-push-timeout-time = 10s
}
akka.actor.mailbox.requirements {
"akka.dispatch.BoundedMessageQueueSemantics" = bounded-mailbox
}
Now every time you create an actor of type MyBoundedActor
it will try to get a bounded
mailbox. If the actor has a different mailbox configured in deployment, either directly or via
a dispatcher with a specified mailbox type, then that will override this mapping.
Note
The type of the queue in the mailbox created for an actor will be checked against the required type in the trait and if the queue doesn't implement the required type then actor creation will fail.
Requiring a Message Queue Type for a Dispatcher
A dispatcher may also have a requirement for the mailbox type used by the actors running on it. An example is the BalancingDispatcher which requires a message queue that is thread-safe for multiple concurrent consumers. Such a requirement is formulated within the dispatcher configuration section like this:
my-dispatcher {
mailbox-requirement = org.example.MyInterface
}
The given requirement names a class or interface which will then be ensured to be a supertype of the message queue’s implementation. In case of a conflict—e.g. if the actor requires a mailbox type which does not satisfy this requirement—then actor creation will fail.
How the Mailbox Type is Selected
When an actor is created, the ActorRefProvider
first determines the
dispatcher which will execute it. Then the mailbox is determined as follows:
- If the actor’s deployment configuration section contains a
mailbox
key then that names a configuration section describing the mailbox type to be used. - If the actor’s
Props
contains a mailbox selection—i.e.withMailbox
was called on it—then that names a configuration section describing the mailbox type to be used. - If the dispatcher’s configuration section contains a
mailbox-type
key the same section will be used to configure the mailbox type. - If the actor requires a mailbox type as described above then the mapping for that requirement will be used to determine the mailbox type to be used; if that fails then the dispatcher’s requirement—if any—will be tried instead.
- If the dispatcher requires a mailbox type as described above then the mapping for that requirement will be used to determine the mailbox type to be used.
- The default mailbox
akka.actor.default-mailbox
will be used.
Default Mailbox
When the mailbox is not specified as described above the default mailbox
is used. By default it is an unbounded mailbox, which is backed by a
java.util.concurrent.ConcurrentLinkedQueue
.
SingleConsumerOnlyUnboundedMailbox
is an even more efficient mailbox, and
it can be used as the default mailbox, but it cannot be used with a BalancingDispatcher.
Configuration of SingleConsumerOnlyUnboundedMailbox
as default mailbox:
akka.actor.default-mailbox {
mailbox-type = "akka.dispatch.SingleConsumerOnlyUnboundedMailbox"
}
Which Configuration is passed to the Mailbox Type
Each mailbox type is implemented by a class which extends MailboxType
and takes two constructor arguments: a ActorSystem.Settings
object and
a Config
section. The latter is computed by obtaining the named
configuration section from the actor system’s configuration, overriding its
id
key with the configuration path of the mailbox type and adding a
fall-back to the default mailbox configuration section.
Builtin implementations
Akka comes shipped with a number of mailbox implementations:
UnboundedMailbox - The default mailbox
- Backed by a
java.util.concurrent.ConcurrentLinkedQueue
- Blocking: No
- Bounded: No
- Configuration name: "unbounded" or "akka.dispatch.UnboundedMailbox"
- Backed by a
SingleConsumerOnlyUnboundedMailbox
This queue may or may not be faster than the default one depending on your use-case—be sure to benchmark properly!
- Backed by a Multiple-Producer Single-Consumer queue, cannot be used with
BalancingDispatcher
- Blocking: No
- Bounded: No
- Configuration name: "akka.dispatch.SingleConsumerOnlyUnboundedMailbox"
- Backed by a Multiple-Producer Single-Consumer queue, cannot be used with
BoundedMailbox
- Backed by a
java.util.concurrent.LinkedBlockingQueue
- Blocking: Yes
- Bounded: Yes
- Configuration name: "bounded" or "akka.dispatch.BoundedMailbox"
- Backed by a
UnboundedPriorityMailbox
- Backed by a
java.util.concurrent.PriorityBlockingQueue
- Blocking: Yes
- Bounded: No
- Configuration name: "akka.dispatch.UnboundedPriorityMailbox"
- Backed by a
BoundedPriorityMailbox
- Backed by a
java.util.PriorityBlockingQueue
wrapped in anakka.util.BoundedBlockingQueue
- Blocking: Yes
- Bounded: Yes
- Configuration name: "akka.dispatch.BoundedPriorityMailbox"
- Backed by a
Mailbox configuration examples
How to create a PriorityMailbox:
import akka.dispatch.PriorityGenerator
import akka.dispatch.UnboundedPriorityMailbox
import com.typesafe.config.Config
// We inherit, in this case, from UnboundedPriorityMailbox
// and seed it with the priority generator
class MyPrioMailbox(settings: ActorSystem.Settings, config: Config)
extends UnboundedPriorityMailbox(
// Create a new PriorityGenerator, lower prio means more important
PriorityGenerator {
// 'highpriority messages should be treated first if possible
case 'highpriority => 0
// 'lowpriority messages should be treated last if possible
case 'lowpriority => 2
// PoisonPill when no other left
case PoisonPill => 3
// We default to 1, which is in between high and low
case otherwise => 1
})
And then add it to the configuration:
prio-dispatcher {
mailbox-type = "docs.dispatcher.DispatcherDocSpec$MyPrioMailbox"
//Other dispatcher configuration goes here
}
And then an example on how you would use it:
// We create a new Actor that just prints out what it processes
class Logger extends Actor {
val log: LoggingAdapter = Logging(context.system, this)
self ! 'lowpriority
self ! 'lowpriority
self ! 'highpriority
self ! 'pigdog
self ! 'pigdog2
self ! 'pigdog3
self ! 'highpriority
self ! PoisonPill
def receive = {
case x => log.info(x.toString)
}
}
val a = system.actorOf(Props(classOf[Logger], this).withDispatcher(
"prio-dispatcher"))
/*
* Logs:
* 'highpriority
* 'highpriority
* 'pigdog
* 'pigdog2
* 'pigdog3
* 'lowpriority
* 'lowpriority
*/
It is also possible to configure a mailbox type directly like this:
prio-mailbox {
mailbox-type = "docs.dispatcher.DispatcherDocSpec$MyPrioMailbox"
//Other mailbox configuration goes here
}
akka.actor.deployment {
/priomailboxactor {
mailbox = prio-mailbox
}
}
And then use it either from deployment like this:
import akka.actor.Props
val myActor = context.actorOf(Props[MyActor], "priomailboxactor")
Or code like this:
import akka.actor.Props
val myActor = context.actorOf(Props[MyActor].withMailbox("prio-mailbox"))
Creating your own Mailbox type
An example is worth a thousand quacks:
import akka.actor.ActorRef
import akka.actor.ActorSystem
import akka.dispatch.Envelope
import akka.dispatch.MailboxType
import akka.dispatch.MessageQueue
import akka.dispatch.ProducesMessageQueue
import com.typesafe.config.Config
import java.util.concurrent.ConcurrentLinkedQueue
import scala.Option
// Marker trait used for mailbox requirements mapping
trait MyUnboundedMessageQueueSemantics
object MyUnboundedMailbox {
// This is the MessageQueue implementation
class MyMessageQueue extends MessageQueue
with MyUnboundedMessageQueueSemantics {
private final val queue = new ConcurrentLinkedQueue[Envelope]()
// these should be implemented; queue used as example
def enqueue(receiver: ActorRef, handle: Envelope): Unit =
queue.offer(handle)
def dequeue(): Envelope = queue.poll()
def numberOfMessages: Int = queue.size
def hasMessages: Boolean = !queue.isEmpty
def cleanUp(owner: ActorRef, deadLetters: MessageQueue) {
while (hasMessages) {
deadLetters.enqueue(owner, dequeue())
}
}
}
}
// This is the Mailbox implementation
class MyUnboundedMailbox extends MailboxType
with ProducesMessageQueue[MyUnboundedMailbox.MyMessageQueue] {
import MyUnboundedMailbox._
// This constructor signature must exist, it will be called by Akka
def this(settings: ActorSystem.Settings, config: Config) = {
// put your initialization code here
this()
}
// The create method is called to create the MessageQueue
final override def create(owner: Option[ActorRef],
system: Option[ActorSystem]): MessageQueue =
new MyMessageQueue()
}
And then you just specify the FQCN of your MailboxType as the value of the "mailbox-type" in the dispatcher configuration, or the mailbox configuration.
Note
Make sure to include a constructor which takes
akka.actor.ActorSystem.Settings
and com.typesafe.config.Config
arguments, as this constructor is invoked reflectively to construct your
mailbox type. The config passed in as second argument is that section from
the configuration which describes the dispatcher or mailbox setting using
this mailbox type; the mailbox type will be instantiated once for each
dispatcher or mailbox setting using it.
You can also use the mailbox as a requirement on the dispatcher like this:
custom-dispatcher {
mailbox-requirement =
"docs.dispatcher.MyUnboundedJMessageQueueSemantics"
}
akka.actor.mailbox.requirements {
"docs.dispatcher.MyUnboundedJMessageQueueSemantics" =
custom-dispatcher-mailbox
}
custom-dispatcher-mailbox {
mailbox-type = "docs.dispatcher.MyUnboundedJMailbox"
}
Or by defining the requirement on your actor class like this:
class MySpecialActor extends Actor
with RequiresMessageQueue[MyUnboundedMessageQueueSemantics] {
// ...
}
Special Semantics of system.actorOf
In order to make system.actorOf
both synchronous and non-blocking while
keeping the return type ActorRef
(and the semantics that the returned
ref is fully functional), special handling takes place for this case. Behind
the scenes, a hollow kind of actor reference is constructed, which is sent to
the system’s guardian actor who actually creates the actor and its context and
puts those inside the reference. Until that has happened, messages sent to the
ActorRef
will be queued locally, and only upon swapping the real
filling in will they be transferred into the real mailbox. Thus,
val props: Props = ...
// this actor uses MyCustomMailbox, which is assumed to be a singleton
system.actorOf(props.withDispatcher("myCustomMailbox")) ! "bang"
assert(MyCustomMailbox.instance.getLastEnqueuedMessage == "bang")
will probably fail; you will have to allow for some time to pass and retry the
check à la TestKit.awaitCond
.
Contents