akka-docs/src/main/paradox/mailboxes.md
@@includeincludes.md { #actor-api } For the full documentation of this feature and for new projects see @ref:mailboxes.
@@@note The Akka dependencies are available from Akka’s secure library repository. To access them you need to use a secure, tokenized URL as specified at https://account.akka.io/token. @@@
To use Mailboxes, you must add the following dependency in your project:
@@dependency[sbt,Maven,Gradle] { bomGroup=com.typesafe.akka bomArtifact=akka-bom_$scala.binary.version$ bomVersionSymbols=AkkaVersion symbol1=AkkaVersion value1="$akka.version$" group="com.typesafe.akka" artifact="akka-actor_$scala.binary.version$" version=AkkaVersion }
An Akka Mailbox holds the messages that are destined for an @apidoc[akka.actor.Actor].
Normally each Actor has its own mailbox, but with for example a @apidoc[BalancingPool]
all routees will share a single mailbox instance.
For more details on advanced mailbox config and custom mailbox implementations, see @refMailboxes.
The default mailbox is used when the mailbox is not specified. This is an unbounded mailbox, backed by a @javadocjava.util.concurrent.ConcurrentLinkedQueue.
@apidoc[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"
}
It is possible to require a certain type of message queue for a certain type of actor by having that actor @scala[extend]@java[implement] the parameterized @scala[trait]@java[interface] @apidoc[RequiresMessageQueue]. Here is an example:
Scala : @@snip DispatcherDocSpec.scala { #required-mailbox-class }
Java : @@snip MyBoundedActor.java { #my-bounded-classic-actor }
The type parameter to the RequiresMessageQueue @scala[trait]@java[interface] needs to be mapped to a mailbox in
configuration like this:
@@snip DispatcherDocSpec.scala { #bounded-mailbox-config #required-mailbox-config }
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 @scala[trait]@java[interface] and if the queue doesn't implement the required type then actor creation will fail.
@@@
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:
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.
When an actor is created, the @apidoc[ActorRefProvider] first determines the dispatcher which will execute it. Then the mailbox is determined as follows:
mailbox key,
this refers to a configuration section describing the mailbox type.myapp.special-mailbox, and is not nested inside the akka namespace.mailbox-type key
the same section will be used to configure the mailbox type.akka.actor.default-mailbox will be used.How to create a PriorityMailbox:
Scala : @@snip DispatcherDocSpec.scala { #prio-mailbox }
Java : @@snip DispatcherDocTest.java { #prio-mailbox }
And then add it to the configuration:
@@snip DispatcherDocSpec.scala { #prio-dispatcher-config }
And then an example on how you would use it:
Scala : @@snip DispatcherDocSpec.scala { #prio-dispatcher }
Java : @@snip DispatcherDocTest.java { #prio-dispatcher }
It is also possible to configure a mailbox type directly like this (this is a top-level configuration entry):
Scala : @@snip DispatcherDocSpec.scala { #prio-mailbox-config #mailbox-deployment-config }
Java : @@snip DispatcherDocSpec.scala { #prio-mailbox-config-java #mailbox-deployment-config }
And then use it either from deployment like this:
Scala : @@snip DispatcherDocSpec.scala { #defining-mailbox-in-config }
Java : @@snip DispatcherDocTest.java { #defining-mailbox-in-config }
Or code like this:
Scala : @@snip DispatcherDocSpec.scala { #defining-mailbox-in-code }
Java : @@snip DispatcherDocTest.java { #defining-mailbox-in-code }
A ControlAwareMailbox can be very useful if an actor needs to be able to receive control messages
immediately no matter how many other messages are already in its mailbox.
It can be configured like this:
@@snip DispatcherDocSpec.scala { #control-aware-mailbox-config }
Control messages need to extend the @apidoc[akka.dispatch.ControlMessage] @scala[trait]@java[interface]:
Scala : @@snip DispatcherDocSpec.scala { #control-aware-mailbox-messages }
Java : @@snip DispatcherDocTest.java { #control-aware-mailbox-messages }
And then an example on how you would use it:
Scala : @@snip DispatcherDocSpec.scala { #control-aware-dispatcher }
Java : @@snip DispatcherDocTest.java { #control-aware-dispatcher }
system.actorOfIn order to make @apidocsystem.actorOf {scala="#actorOf(props:akka.actor.Props):akka.actor.ActorRef" java="#actorOf(akka.actor.Props)"} both synchronous and non-blocking while keeping the return type @apidoc[akka.actor.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 @apidoc[akka.actor.ActorRef] will be queued locally, and only upon swapping the real filling in will they be transferred into the real mailbox. Thus,
Scala
: @@@vars
scala 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")
@@@
Java
: @@@vars
java final Props props = ... // this actor uses MyCustomMailbox, which is assumed to be a singleton system.actorOf(props.withDispatcher("myCustomMailbox").tell("bang", sender); assert(MyCustomMailbox.getInstance().getLastEnqueued().equals("bang"));
@@@
will probably fail; you will have to allow for some time to pass and retry the check à la @scala[@scaladocTestKit.awaitCond]@java[@javadocTestKit.awaitCond].