Merge akka-docs/paradox/scala/actors.md and java/actors.md (#23079)
* Identical contents in scala/actors.md and java/actors.md * Replace java/actors.md with a symlink to scala/actors.md
This commit is contained in:
parent
fb3e42f2e8
commit
c569bdbc7c
5 changed files with 489 additions and 1188 deletions
File diff suppressed because it is too large
Load diff
1
akka-docs/src/main/paradox/java/actors.md
Symbolic link
1
akka-docs/src/main/paradox/java/actors.md
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../scala/actors.md
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
# Java 8 and Scala Compatibility
|
||||
|
||||
Akka requires that you have [Java 8](http://www.oracle.com/technetwork/java/javase/downloads/index.html) or
|
||||
later installed on your machine.
|
||||
|
||||
## Java 8 types
|
||||
|
||||
Starting with Akka 2.4.2 we have begun to introduce Java 8 types (most
|
||||
prominently `java.util.concurrent.CompletionStage` and
|
||||
`java.util.Optional`) where that was possible without breaking binary or
|
||||
source compatibility. Where this was not possible (for example in the return
|
||||
type of `ActorSystem.terminate()`) please refer to the
|
||||
`scala-java8-compat` library that allows easy conversion between the Scala
|
||||
and Java counterparts. The artifact can be included in Maven builds using:
|
||||
|
||||
```
|
||||
<dependency>
|
||||
<groupId>org.scala-lang.modules</groupId>
|
||||
<artifactId>scala-java8-compat_2.11</artifactId>
|
||||
<version>0.7.0</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
We will only be able to seamlessly integrate all functional interfaces once
|
||||
we can rely on Scala 2.12 to provide full interoperability—this will mean that
|
||||
Scala users can directly implement Java Functional Interfaces using lambda syntax
|
||||
as well as that Java users can directly implement Scala functions using lambda
|
||||
syntax.
|
||||
|
||||
## Do not use -optimize Scala compiler flag
|
||||
|
||||
@@@ warning
|
||||
|
||||
Akka has not been compiled or tested with -optimize Scala compiler flag.
|
||||
Strange behavior has been reported by users that have tried it.
|
||||
|
||||
@@@
|
||||
1
akka-docs/src/main/paradox/java/scala-compat.md
Symbolic link
1
akka-docs/src/main/paradox/java/scala-compat.md
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../scala/scala-compat.md
|
||||
|
|
@ -24,15 +24,38 @@ and it may also help to read @ref:[Actor References, Paths and Addresses](genera
|
|||
|
||||
### Defining an Actor class
|
||||
|
||||
@@@ div { .group-scala }
|
||||
|
||||
Actors are implemented by extending the `Actor` base trait and implementing the
|
||||
`receive` method. The `receive` method should define a series of case
|
||||
statements (which has the type `PartialFunction[Any, Unit]`) that defines
|
||||
which messages your Actor can handle, using standard Scala pattern matching,
|
||||
along with the implementation of how the messages should be processed.
|
||||
|
||||
@@@
|
||||
|
||||
@@@ div { .group-java }
|
||||
|
||||
Actor classes are implemented by extending the `AbstractActor` class and setting
|
||||
the “initial behavior” in the constructor by calling the `receive` method in
|
||||
the `AbstractActor`.
|
||||
|
||||
The argument to the `receive` method is a `PartialFunction<Object,BoxedUnit>`
|
||||
that defines which messages your Actor can handle, along with the implementation of
|
||||
how the messages should be processed.
|
||||
|
||||
Don't let the type signature scare you. To allow you to easily build up a partial
|
||||
function there is a builder named `ReceiveBuilder` that you can use.
|
||||
|
||||
@@@
|
||||
|
||||
Here is an example:
|
||||
|
||||
@@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #imports1 #my-actor }
|
||||
Scala
|
||||
: @@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #imports1 #my-actor }
|
||||
|
||||
Java
|
||||
: @@snip [MyActor.java]($code$/java/jdocs/actor/MyActor.java) { #imports #my-actor }
|
||||
|
||||
Please note that the Akka Actor `receive` message loop is exhaustive, which
|
||||
is different compared to Erlang and the late Scala Actors. This means that you
|
||||
|
|
@ -46,17 +69,19 @@ Note further that the return type of the behavior defined above is `Unit`; if
|
|||
the actor shall reply to the received message then this must be done explicitly
|
||||
as explained below.
|
||||
|
||||
The result of the `receive` method is a partial function object, which is
|
||||
The @scala[result of] @java[argument to] the `receive` method is a partial function object, which is
|
||||
stored within the actor as its “initial behavior”, see [Become/Unbecome](#become-unbecome) for
|
||||
further information on changing the behavior of an actor after its
|
||||
construction.
|
||||
|
||||
@@@ div { .group-scala }
|
||||
|
||||
#### Here is another example that you can edit and run in the browser:
|
||||
|
||||
@@fiddle [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #fiddle_code height=400px extraParams=theme=light&layout=v75 cssStyle=width:100%; }
|
||||
|
||||
|
||||
@@@
|
||||
|
||||
### Props
|
||||
|
||||
`Props` is a configuration class to specify options for the creation
|
||||
|
|
@ -65,7 +90,12 @@ creating an actor including associated deployment information (e.g. which
|
|||
dispatcher to use, see more below). Here are some examples of how to create a
|
||||
`Props` instance.
|
||||
|
||||
@@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #creating-props }
|
||||
Scala
|
||||
: @@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #creating-props }
|
||||
|
||||
Java
|
||||
: @@snip [ActorDocTest.java]($code$/java/jdocs/actor/ActorDocTest.java) { #import-props #creating-props }
|
||||
|
||||
|
||||
The second variant shows how to pass constructor arguments to the
|
||||
`Actor` being created, but it should only be used outside of actors as
|
||||
|
|
@ -77,7 +107,7 @@ verified during construction of the `Props` object, resulting in an
|
|||
`IllegalArgumentException` if no or multiple matching constructors are
|
||||
found.
|
||||
|
||||
@@@ note
|
||||
@@@ note { .group-scala }
|
||||
|
||||
The recommended approach to create the actor `Props` is not supported
|
||||
for cases when the actor constructor takes value classes as arguments.
|
||||
|
|
@ -85,8 +115,11 @@ for cases when the actor constructor takes value classes as arguments.
|
|||
@@@
|
||||
|
||||
#### Dangerous Variants
|
||||
Scala
|
||||
: @@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #creating-props-deprecated }
|
||||
|
||||
@@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #creating-props-deprecated }
|
||||
Java
|
||||
: @@snip [ActorDocTest.java]($code$/java/jdocs/actor/ActorDocTest.java) { #creating-props-deprecated }
|
||||
|
||||
This method is not recommended to be used within another actor because it
|
||||
encourages to close over the enclosing scope, resulting in non-serializable
|
||||
|
|
@ -97,7 +130,7 @@ is completely fine.
|
|||
|
||||
There were two use-cases for these methods: passing constructor arguments to
|
||||
the actor—which is solved by the newly introduced
|
||||
`Props.apply(clazz, args)` method above or the recommended practice
|
||||
@scala[`Props.apply(clazz, args)`] @java[`Props.create(clazz, args)`] method above or the recommended practice
|
||||
below—and creating actors “on the spot” as anonymous classes. The latter should
|
||||
be solved by making these actors named classes instead (if they are not
|
||||
declared within a top-level `object` then the enclosing instance’s `this`
|
||||
|
|
@ -110,6 +143,8 @@ encapsulation. Never pass an actor’s `this` reference into `Props`!
|
|||
|
||||
@@@
|
||||
|
||||
@@@ div { .group-scala }
|
||||
|
||||
#### Edge cases
|
||||
|
||||
There are two edge cases in actor creation with `Props`:
|
||||
|
|
@ -130,22 +165,33 @@ no matching constructor could be found.
|
|||
The next section explains the recommended ways to create `Actor` props in a way,
|
||||
which simultaneously safe-guards against these edge cases.
|
||||
|
||||
@@@
|
||||
|
||||
#### Recommended Practices
|
||||
|
||||
It is a good idea to provide factory methods on the companion object of each
|
||||
`Actor` which help keeping the creation of suitable `Props` as
|
||||
close to the actor definition as possible. This also avoids the pitfalls
|
||||
associated with using the `Props.apply(...)` method which takes a by-name
|
||||
associated with using the @scala[`Props.apply(...)`] @java[ `Props.create(...)`] method which takes a by-name
|
||||
argument, since within a companion object the given code block will not retain
|
||||
a reference to its enclosing scope:
|
||||
|
||||
@@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #props-factory }
|
||||
Scala
|
||||
: @@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #props-factory }
|
||||
|
||||
Java
|
||||
: @@snip [ActorDocTest.java]($code$/java/jdocs/actor/ActorDocTest.java) { #props-factory }
|
||||
|
||||
Another good practice is to declare what messages an Actor can receive
|
||||
in the companion object of the Actor, which makes easier
|
||||
to know what it can receive:
|
||||
@scala[in the companion object of the Actor]
|
||||
@java[as close to the actor definition as possible (e.g. as static classes inside the Actor or using other suitable class)],
|
||||
which makes easier to know what it can receive:
|
||||
|
||||
@@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #messages-in-companion }
|
||||
Scala
|
||||
: @@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #messages-in-companion }
|
||||
|
||||
Java
|
||||
: @@snip [ActorDocTest.java]($code$/java/jdocs/actor/ActorDocTest.java) { #messages-in-companion }
|
||||
|
||||
### Creating Actors with Props
|
||||
|
||||
|
|
@ -153,13 +199,21 @@ Actors are created by passing a `Props` instance into the
|
|||
`actorOf` factory method which is available on `ActorSystem` and
|
||||
`ActorContext`.
|
||||
|
||||
@@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #system-actorOf }
|
||||
Scala
|
||||
: @@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #system-actorOf }
|
||||
|
||||
Java
|
||||
: @@snip [ActorDocTest.java]($code$/java/jdocs/actor/ActorDocTest.java) { #import-actorRef }
|
||||
|
||||
Using the `ActorSystem` will create top-level actors, supervised by the
|
||||
actor system’s provided guardian actor, while using an actor’s context will
|
||||
create a child actor.
|
||||
|
||||
@@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #context-actorOf }
|
||||
Scala
|
||||
: @@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #context-actorOf }
|
||||
|
||||
Java
|
||||
: @@snip [ActorDocTest.java]($code$/java/jdocs/actor/ActorDocTest.java) { #context-actorOf }
|
||||
|
||||
It is recommended to create a hierarchy of children, grand-children and so on
|
||||
such that it fits the logical failure-handling structure of the application,
|
||||
|
|
@ -181,6 +235,8 @@ another child to the same parent an `InvalidActorNameException` is thrown.
|
|||
|
||||
Actors are automatically started asynchronously when created.
|
||||
|
||||
@@@ div { .group-scala }
|
||||
|
||||
#### Value classes as constructor arguments
|
||||
|
||||
The recommended way to instantiate actor props uses reflection at runtime
|
||||
|
|
@ -192,19 +248,25 @@ calling the constructor manually:
|
|||
|
||||
@@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #actor-with-value-class-argument }
|
||||
|
||||
@@@
|
||||
|
||||
### Dependency Injection
|
||||
|
||||
If your Actor has a constructor that takes parameters then those need to
|
||||
If your `Actor` has a constructor that takes parameters then those need to
|
||||
be part of the `Props` as well, as described [above](Props_). But there
|
||||
are cases when a factory method must be used, for example when the actual
|
||||
constructor arguments are determined by a dependency injection framework.
|
||||
|
||||
@@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #creating-indirectly }
|
||||
Scala
|
||||
: @@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #creating-indirectly }
|
||||
|
||||
Java
|
||||
: @@snip [DependencyInjectionDocTest.java]($code$/java/jdocs/actor/DependencyInjectionDocTest.java) { #import #creating-indirectly }
|
||||
|
||||
@@@ warning
|
||||
|
||||
You might be tempted at times to offer an `IndirectActorProducer`
|
||||
which always returns the same instance, e.g. by using a `lazy val`. This is
|
||||
which always returns the same instance, e.g. by using a @scala[`lazy val`.] @java[static field.] This is
|
||||
not supported, as it goes against the meaning of an actor restart, which is
|
||||
described here: @ref:[What Restarting Means](general/supervision.md#supervision-restart).
|
||||
|
||||
|
|
@ -226,7 +288,14 @@ cannot do: receiving multiple replies (e.g. by subscribing an `ActorRef`
|
|||
to a notification service) and watching other actors’ lifecycle. For these
|
||||
purposes there is the `Inbox` class:
|
||||
|
||||
@@snip [ActorDSLSpec.scala]($akka$/akka-actor-tests/src/test/scala/akka/actor/ActorDSLSpec.scala) { #inbox }
|
||||
Scala
|
||||
: @@snip [ActorDSLSpec.scala]($akka$/akka-actor-tests/src/test/scala/akka/actor/ActorDSLSpec.scala) { #inbox }
|
||||
|
||||
Java
|
||||
: @@snip [InboxDocTest.java]($code$/java/jdocs/actor/InboxDocTest.java) { #inbox }
|
||||
|
||||
|
||||
@@@ div { .group-scala }
|
||||
|
||||
There is an implicit conversion from inbox to actor reference which means that
|
||||
in this example the sender reference will be that of the actor hidden away
|
||||
|
|
@ -235,10 +304,24 @@ Watching an actor is quite simple as well:
|
|||
|
||||
@@snip [ActorDSLSpec.scala]($akka$/akka-actor-tests/src/test/scala/akka/actor/ActorDSLSpec.scala) { #watch }
|
||||
|
||||
@@@
|
||||
|
||||
@@@ div { .group-java }
|
||||
|
||||
The `send` method wraps a normal `tell` and supplies the internal
|
||||
actor’s reference as the sender. This allows the reply to be received on the
|
||||
last line. Watching an actor is quite simple as well:
|
||||
|
||||
@@snip [InboxDocTest.java]($code$/java/jdocs/actor/InboxDocTest.java) { #watch }
|
||||
|
||||
@@@
|
||||
|
||||
## Actor API
|
||||
|
||||
The `Actor` trait defines only one abstract method, the above mentioned
|
||||
`receive`, which implements the behavior of the actor.
|
||||
@scala[The `Actor` trait defines only one abstract method, the above mentioned
|
||||
`receive`, which implements the behavior of the actor.]
|
||||
@java[The `AbstractActor` class defines a method called `receive`,
|
||||
that is used to set the “initial behavior” of the actor.]
|
||||
|
||||
If the current actor behavior does not match a received message,
|
||||
`unhandled` is called, which by default publishes an
|
||||
|
|
@ -248,11 +331,13 @@ system’s event stream (set configuration item
|
|||
actual Debug messages).
|
||||
|
||||
In addition, it offers:
|
||||
|
||||
* `self` reference to the `ActorRef` of the actor
|
||||
* `sender` reference sender Actor of the last received message, typically used as described in [Actor.Reply](#actor-reply)
|
||||
*
|
||||
`supervisorStrategy` user overridable definition the strategy to use for supervising child actors
|
||||
|
||||
* @scala[`self`] @java[`getSelf()`] reference to the `ActorRef` of the actor
|
||||
* @scala[`sender`] @java[`getSender()`] reference sender Actor of the last received message, typically used as described in
|
||||
@scala[[Actor.Reply](#actor-reply)]
|
||||
@java[[LambdaActor.Reply](#lambdaactor-reply)]
|
||||
* @scala[`supervisorStrategy`] @java[`supervisorStrategy()`] user overridable definition the strategy to use for supervising child actors
|
||||
|
||||
This strategy is typically declared inside the actor in order to have access
|
||||
to the actor’s internal state within the decider function: since failure is
|
||||
communicated as a message sent to the supervisor and processed like other
|
||||
|
|
@ -261,26 +346,33 @@ within the actor are available, as is the `sender` reference (which will
|
|||
be the immediate child reporting the failure; if the original failure
|
||||
occurred within a distant descendant it is still reported one level up at a
|
||||
time).
|
||||
*
|
||||
`context` exposes contextual information for the actor and the current message, such as:
|
||||
|
||||
* @scala[`context`] @java[`getContext()`] exposes contextual information for the actor and the current message, such as:
|
||||
* factory methods to create child actors (`actorOf`)
|
||||
* system that the actor belongs to
|
||||
* parent supervisor
|
||||
* supervised children
|
||||
* lifecycle monitoring
|
||||
* hotswap behavior stack as described in [Actor.HotSwap](#actor-hotswap)
|
||||
* hotswap behavior stack as described in @scala[[Actor.HotSwap](#actor-hotswap)] @java[[Become/Unbecome](#actor-hotswap)]
|
||||
|
||||
@@@ div { .group-scala }
|
||||
|
||||
You can import the members in the `context` to avoid prefixing access with `context.`
|
||||
|
||||
@@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #import-context }
|
||||
|
||||
@@@
|
||||
|
||||
The remaining visible methods are user-overridable life-cycle hooks which are
|
||||
described in the following:
|
||||
|
||||
@@snip [Actor.scala]($akka$/akka-actor/src/main/scala/akka/actor/Actor.scala) { #lifecycle-hooks }
|
||||
Scala
|
||||
: @@snip [Actor.scala]($akka$/akka-actor/src/main/scala/akka/actor/Actor.scala) { #lifecycle-hooks }
|
||||
|
||||
The implementations shown above are the defaults provided by the `Actor`
|
||||
trait.
|
||||
Java
|
||||
: @@snip [ActorDocTest.java]($code$/java/jdocs/actor/ActorDocTest.java) { #lifecycle-callbacks }
|
||||
|
||||
The implementations shown above are the defaults provided by the @scala[`Actor` trait.] @java[`AbstractActor` class.]
|
||||
|
||||
<a id="actor-lifecycle"></a>
|
||||
### Actor Lifecycle
|
||||
|
|
@ -338,7 +430,11 @@ termination (see [Stopping Actors](#stopping-actors)). This service is provided
|
|||
|
||||
Registering a monitor is easy:
|
||||
|
||||
@@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #watch }
|
||||
Scala
|
||||
: @@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #watch }
|
||||
|
||||
Java
|
||||
: @@snip [ActorDocTest.java]($code$/java/jdocs/actor/ActorDocTest.java) { #import-terminated #watch }
|
||||
|
||||
It should be noted that the `Terminated` message is generated
|
||||
independent of the order in which registration and termination occur.
|
||||
|
|
@ -363,7 +459,11 @@ no `Terminated` message for that actor will be processed anymore.
|
|||
|
||||
Right after starting the actor, its `preStart` method is invoked.
|
||||
|
||||
@@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #preStart }
|
||||
Scala
|
||||
: @@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #preStart }
|
||||
|
||||
Java
|
||||
: @@snip [ActorDocTest.java]($code$/java/jdocs/actor/ActorDocTest.java) { #preStart }
|
||||
|
||||
This method is called when the actor is first created. During restarts it is
|
||||
called by the default implementation of `postRestart`, which means that
|
||||
|
|
@ -436,7 +536,11 @@ actors may look up other actors by specifying absolute or relative
|
|||
paths—logical or physical—and receive back an `ActorSelection` with the
|
||||
result:
|
||||
|
||||
@@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #selection-local }
|
||||
Scala
|
||||
: @@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #selection-local }
|
||||
|
||||
Java
|
||||
: @@snip [ActorDocTest.java]($code$/java/jdocs/actor/ActorDocTest.java) { #selection-local }
|
||||
|
||||
@@@ note
|
||||
|
||||
|
|
@ -464,14 +568,18 @@ structure, i.e. the supervisor.
|
|||
The path elements of an actor selection may contain wildcard patterns allowing for
|
||||
broadcasting of messages to that section:
|
||||
|
||||
@@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #selection-wildcard }
|
||||
Scala
|
||||
: @@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #selection-wildcard }
|
||||
|
||||
Java
|
||||
: @@snip [ActorDocTest.java]($code$/java/jdocs/actor/ActorDocTest.java) { #selection-wildcard }
|
||||
|
||||
Messages can be sent via the `ActorSelection` and the path of the
|
||||
`ActorSelection` is looked up when delivering each message. If the selection
|
||||
does not match any actors the message will be dropped.
|
||||
|
||||
To acquire an `ActorRef` for an `ActorSelection` you need to send
|
||||
a message to the selection and use the `sender()` reference of the reply from
|
||||
a message to the selection and use the @scala[`sender()`] @java[`getSender()`] reference of the reply from
|
||||
the actor. There is a built-in `Identify` message that all Actors will
|
||||
understand and automatically reply to with a `ActorIdentity` message
|
||||
containing the `ActorRef`. This message is handled specially by the
|
||||
|
|
@ -480,17 +588,26 @@ actors which are traversed in the sense that if a concrete name lookup fails
|
|||
negative result is generated. Please note that this does not mean that delivery
|
||||
of that reply is guaranteed, it still is a normal message.
|
||||
|
||||
@@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #identify }
|
||||
Scala
|
||||
: @@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #identify }
|
||||
|
||||
Java
|
||||
: @@snip [ActorDocTest.java]($code$/java/jdocs/actor/ActorDocTest.java) { #import-identify #identify }
|
||||
|
||||
You can also acquire an `ActorRef` for an `ActorSelection` with
|
||||
the `resolveOne` method of the `ActorSelection`. It returns a `Future`
|
||||
of the matching `ActorRef` if such an actor exists. It is completed with
|
||||
of the matching `ActorRef` if such an actor exists. @java[(see also
|
||||
@ref:[Java 8 and Scala Compatibility](scala-compat.md) for Java compatibility).] It is completed with
|
||||
failure [[akka.actor.ActorNotFound]] if no such actor exists or the identification
|
||||
didn't complete within the supplied *timeout*.
|
||||
didn't complete within the supplied `timeout`.
|
||||
|
||||
Remote actor addresses may also be looked up, if @ref:[remoting](remoting.md) is enabled:
|
||||
|
||||
@@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #selection-remote }
|
||||
Scala
|
||||
: @@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #selection-remote }
|
||||
|
||||
Java
|
||||
: @@snip [ActorDocTest.java]($code$/java/jdocs/actor/ActorDocTest.java) { #selection-remote }
|
||||
|
||||
An example demonstrating actor look-up is given in @ref:[Remoting Sample](remoting.md#remote-sample).
|
||||
|
||||
|
|
@ -498,32 +615,31 @@ An example demonstrating actor look-up is given in @ref:[Remoting Sample](remoti
|
|||
|
||||
@@@ warning { title=IMPORTANT }
|
||||
|
||||
Messages can be any kind of object but have to be immutable. Scala can’t enforce
|
||||
immutability (yet) so this has to be by convention. Primitives like String, Int,
|
||||
Messages can be any kind of object but have to be immutable. @scala[Scala] @java[Akka] can’t enforce
|
||||
immutability (yet) so this has to be by convention. @scala[Primitives like String, Int,
|
||||
Boolean are always immutable. Apart from these the recommended approach is to
|
||||
use Scala case classes which are immutable (if you don’t explicitly expose the
|
||||
state) and works great with pattern matching at the receiver side.
|
||||
state) and works great with pattern matching at the receiver side.]
|
||||
|
||||
@@@
|
||||
|
||||
Here is an example:
|
||||
Here is an @scala[example:] @java[example of an immutable message:]
|
||||
|
||||
```scala
|
||||
// define the case class
|
||||
case class Register(user: User)
|
||||
Scala
|
||||
: @@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #immutable-message-definition #immutable-message-instantiation }
|
||||
|
||||
Java
|
||||
: @@snip [ImmutableMessage.java]($code$/java/jdocs/actor/ImmutableMessage.java) { #immutable-message }
|
||||
|
||||
// create a new case class message
|
||||
val message = Register(user)
|
||||
```
|
||||
|
||||
## Send messages
|
||||
|
||||
Messages are sent to an Actor through one of the following methods.
|
||||
|
||||
* `!` means “fire-and-forget”, e.g. send a message asynchronously and return
|
||||
immediately. Also known as `tell`.
|
||||
* `?` sends a message asynchronously and returns a `Future`
|
||||
representing a possible reply. Also known as `ask`.
|
||||
* @scala[`!`] @java[`tell` ] means “fire-and-forget”, e.g. send a message asynchronously and return
|
||||
immediately. @scala[Also known as `tell`.]
|
||||
* @scala[`?`] @java[`ask`] sends a message asynchronously and returns a `Future`
|
||||
representing a possible reply. @scala[Also known as `ask`].
|
||||
|
||||
Message ordering is guaranteed on a per-sender basis.
|
||||
|
||||
|
|
@ -536,13 +652,27 @@ remoting. So always prefer `tell` for performance, and only `ask` if you must.
|
|||
|
||||
@@@
|
||||
|
||||
@@@ div { .group-java }
|
||||
|
||||
In all these methods you have the option of passing along your own `ActorRef`.
|
||||
Make it a practice of doing so because it will allow the receiver actors to be able to respond
|
||||
to your message, since the sender reference is sent along with the message.
|
||||
|
||||
@@@
|
||||
|
||||
<a id="actors-tell-sender"></a>
|
||||
### Tell: Fire-forget
|
||||
|
||||
This is the preferred way of sending messages. No blocking waiting for a
|
||||
message. This gives the best concurrency and scalability characteristics.
|
||||
|
||||
@@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #tell }
|
||||
Scala
|
||||
: @@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #tell }
|
||||
|
||||
Java
|
||||
: @@snip [ActorDocTest.java]($code$/java/jdocs/actor/ActorDocTest.java) { #tell }
|
||||
|
||||
@@@ div { .group-scala }
|
||||
|
||||
If invoked from within an Actor, then the sending actor reference will be
|
||||
implicitly passed along with the message and available to the receiving Actor
|
||||
|
|
@ -552,28 +682,55 @@ to reply to the original sender, by using `sender() ! replyMsg`.
|
|||
If invoked from an instance that is **not** an Actor the sender will be
|
||||
`deadLetters` actor reference by default.
|
||||
|
||||
@@@
|
||||
|
||||
@@@ div { .group-java }
|
||||
|
||||
The sender reference is passed along with the message and available within the
|
||||
receiving actor via its `getSender()` method while processing this
|
||||
message. Inside of an actor it is usually `getSelf()` who shall be the
|
||||
sender, but there can be cases where replies shall be routed to some other
|
||||
actor—e.g. the parent—in which the second argument to `tell` would be a
|
||||
different one. Outside of an actor and if no reply is needed the second
|
||||
argument can be `null`; if a reply is needed outside of an actor you can use
|
||||
the ask-pattern described next..
|
||||
|
||||
@@@
|
||||
|
||||
<a id="actors-ask"></a>
|
||||
### Ask: Send-And-Receive-Future
|
||||
|
||||
The `ask` pattern involves actors as well as futures, hence it is offered as
|
||||
a use pattern rather than a method on `ActorRef`:
|
||||
|
||||
@@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #ask-pipeTo }
|
||||
Scala
|
||||
: @@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #ask-pipeTo }
|
||||
|
||||
Java
|
||||
: @@snip [ActorDocTest.java]($code$/java/jdocs/actor/ActorDocTest.java) { #import-ask #ask-pipe }
|
||||
|
||||
|
||||
This example demonstrates `ask` together with the `pipeTo` pattern on
|
||||
futures, because this is likely to be a common combination. Please note that
|
||||
all of the above is completely non-blocking and asynchronous: `ask` produces
|
||||
a `Future`, three of which are composed into a new future using the
|
||||
for-comprehension and then `pipeTo` installs an `onComplete`-handler on the
|
||||
future to affect the submission of the aggregated `Result` to another
|
||||
actor.
|
||||
a `Future`, @scala[three] @java[two] of which are composed into a new future using the
|
||||
@scala[for-comprehension and then `pipeTo` installs an `onComplete`-handler on the future to affect]
|
||||
@java[`Futures.sequence` and `map` methods and then `pipe` installs an `onComplete`-handler on the future to effect]
|
||||
the submission of the aggregated `Result` to another actor.
|
||||
|
||||
Using `ask` will send a message to the receiving Actor as with `tell`, and
|
||||
the receiving actor must reply with `sender() ! reply` in order to complete the
|
||||
returned `Future` with a value. The `ask` operation involves creating
|
||||
the receiving actor must reply with @scala[`sender() ! reply`] @java[`getSender().tell(reply, getSelf())` ] in order to
|
||||
complete the returned `Future` with a value. The `ask` operation involves creating
|
||||
an internal actor for handling this reply, which needs to have a timeout after
|
||||
which it is destroyed in order not to leak resources; see more below.
|
||||
|
||||
@@@ note { .group-java }
|
||||
|
||||
A variant of the `ask` pattern that returns a `CompletionStage` instead of a Scala `Future`
|
||||
is available in the `akka.pattern.PatternsCS` object.
|
||||
|
||||
@@@
|
||||
|
||||
@@@ warning
|
||||
|
||||
To complete the future with an exception you need send a Failure message to the sender.
|
||||
|
|
@ -581,11 +738,17 @@ This is *not done automatically* when an actor throws an exception while process
|
|||
|
||||
@@@
|
||||
|
||||
@@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #reply-exception }
|
||||
Scala
|
||||
: @@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #reply-exception }
|
||||
|
||||
If the actor does not complete the future, it will expire after the timeout
|
||||
period, completing it with an `AskTimeoutException`. The timeout is
|
||||
taken from one of the following locations in order of precedence:
|
||||
Java
|
||||
: @@snip [ActorDocTest.java]($code$/java/jdocs/actor/ActorDocTest.java) { #reply-exception }
|
||||
|
||||
If the actor does not complete the future, it will expire after the timeout period,
|
||||
@scala[completing it with an `AskTimeoutException`. The timeout is taken from one of the following locations in order of precedence:]
|
||||
@java[specified as parameter to the `ask` method; this will complete the `Future` with an `AskTimeoutException`.]
|
||||
|
||||
@@@ div { .group-scala }
|
||||
|
||||
1. explicitly given timeout as in:
|
||||
|
||||
|
|
@ -595,6 +758,8 @@ taken from one of the following locations in order of precedence:
|
|||
|
||||
@@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #using-implicit-timeout }
|
||||
|
||||
@@@
|
||||
|
||||
See @ref:[Futures](futures.md) for more information on how to await or query a
|
||||
future.
|
||||
|
||||
|
|
@ -604,7 +769,7 @@ you a way to avoid blocking.
|
|||
|
||||
@@@ warning
|
||||
|
||||
When using future callbacks, such as `onComplete`, `onSuccess`, and `onFailure`,
|
||||
When using future callbacks, @scala[such as `onComplete`, `onSuccess`, and `onFailure`,]
|
||||
inside actors you need to carefully avoid closing over
|
||||
the containing actor’s reference, i.e. do not call methods or access mutable state
|
||||
on the enclosing actor from within the callback. This would break the actor
|
||||
|
|
@ -622,51 +787,119 @@ original sender address/reference is maintained even though the message is going
|
|||
through a 'mediator'. This can be useful when writing actors that work as
|
||||
routers, load-balancers, replicators etc.
|
||||
|
||||
@@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #forward }
|
||||
Scala
|
||||
: @@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #forward }
|
||||
|
||||
Java
|
||||
: @@snip [ActorDocTest.java]($code$/java/jdocs/actor/ActorDocTest.java) { #forward }
|
||||
|
||||
## Receive messages
|
||||
|
||||
An Actor has to implement the `receive` method to receive messages:
|
||||
|
||||
@@snip [Actor.scala]($akka$/akka-actor/src/main/scala/akka/actor/Actor.scala) { #receive }
|
||||
An Actor has to
|
||||
@scala[implement the `receive` method to receive messages:]
|
||||
@java[define its initial receive behavior by implementing the `createReceive` method in the `AbstractActor`:]
|
||||
|
||||
Scala
|
||||
: @@snip [Actor.scala]($akka$/akka-actor/src/main/scala/akka/actor/Actor.scala) { #receive }
|
||||
|
||||
Java
|
||||
: @@snip [ActorDocTest.java]($code$/java/jdocs/actor/ActorDocTest.java) { #createReceive }
|
||||
|
||||
@@@ div { .group-scala }
|
||||
|
||||
This method returns a `PartialFunction`, e.g. a ‘match/case’ clause in
|
||||
which the message can be matched against the different case clauses using Scala
|
||||
pattern matching. Here is an example:
|
||||
|
||||
@@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #imports1 #my-actor }
|
||||
@@@
|
||||
|
||||
@@@ div { .group-java }
|
||||
|
||||
The return type is `AbstractActor.Receive` that defines which messages your Actor can handle,
|
||||
along with the implementation of how the messages should be processed.
|
||||
You can build such behavior with a builder named `ReceiveBuilder`. Here is an example:
|
||||
|
||||
@@@
|
||||
|
||||
@Scala
|
||||
: @@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #imports1 #my-actor }
|
||||
|
||||
@Java
|
||||
: @@snip [MyActor.java]($code$/java/jdocs/actor/MyActor.java) { #imports #my-actor }
|
||||
|
||||
@@@ div { .group-java }
|
||||
|
||||
In case you want to provide many `match` cases but want to avoid creating a long call
|
||||
trail, you can split the creation of the builder into multiple statements as in the example:
|
||||
|
||||
@@snip [GraduallyBuiltActor.java]($code$/java/jdocs/actor/GraduallyBuiltActor.java) { #imports #actor }
|
||||
|
||||
Using small methods is a good practice, also in actors. It's recommended to delegate the
|
||||
actual work of the message processing to methods instead of defining a huge `ReceiveBuilder`
|
||||
with lots of code in each lambda. A well structured actor can look like this:
|
||||
|
||||
@@snip [ActorDocTest.java]($code$/java/jdocs/actor/ActorDocTest.java) { #well-structured }
|
||||
|
||||
That has benefits such as:
|
||||
|
||||
* easier to see what kind of messages the actor can handle
|
||||
* readable stack traces in case of exceptions
|
||||
* works better with performance profiling tools
|
||||
* Java HotSpot has a better opportunity for making optimizations
|
||||
|
||||
The `Receive` can be implemented in other ways than using the `ReceiveBuilder` since it in the
|
||||
end is just a wrapper around a Scala `PartialFunction`. In Java, you can implement `PartialFunction` by
|
||||
extending `AbstractPartialFunction`. For example, one could implement an adapter
|
||||
to [Javaslang Pattern Matching DSL](http://www.javaslang.io/javaslang-jdocs/#_pattern_matching).
|
||||
|
||||
If the validation of the `ReceiveBuilder` match logic turns out to be a bottleneck for some of your
|
||||
actors you can consider to implement it at lower level by extending `UntypedAbstractActor` instead
|
||||
of `AbstractActor`. The partial functions created by the `ReceiveBuilder` consist of multiple lambda
|
||||
expressions for every match statement, where each lambda is referencing the code to be run. This is something
|
||||
that the JVM can have problems optimizing and the resulting code might not be as performant as the
|
||||
untyped version. When extending `UntypedAbstractActor` each message is received as an untyped
|
||||
`Object` and you have to inspect and cast it to the actual message type in other ways, like this:
|
||||
|
||||
@@snip [ActorDocTest.java]($code$/java/jdocs/actor/ActorDocTest.java) { #optimized }
|
||||
|
||||
@@@
|
||||
|
||||
<a id="actor-reply"></a>
|
||||
## Reply to messages
|
||||
|
||||
If you want to have a handle for replying to a message, you can use
|
||||
`sender()`, which gives you an ActorRef. You can reply by sending to
|
||||
that ActorRef with `sender() ! replyMsg`. You can also store the ActorRef
|
||||
@scala[`sender()`] @java[`getSender()`], which gives you an ActorRef. You can reply by sending to
|
||||
that ActorRef with @scala[`sender() ! replyMsg`.] @java[`getSender().tell(replyMsg, getSelf())`.] You can also store the ActorRef
|
||||
for replying later, or passing on to other actors. If there is no sender (a
|
||||
message was sent without an actor or future context) then the sender
|
||||
defaults to a 'dead-letter' actor ref.
|
||||
|
||||
```scala
|
||||
case request =>
|
||||
val result = process(request)
|
||||
sender() ! result // will have dead-letter actor as default
|
||||
```
|
||||
Scala
|
||||
: @@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #reply-without-sender }
|
||||
|
||||
Java
|
||||
: @@snip [MyActor.java]($code$/java/jdocs/actor/MyActor.java) { #reply }
|
||||
|
||||
## Receive timeout
|
||||
|
||||
The *ActorContext* `setReceiveTimeout` defines the inactivity timeout after which
|
||||
the sending of a *ReceiveTimeout* message is triggered.
|
||||
When specified, the receive function should be able to handle an *akka.actor.ReceiveTimeout* message.
|
||||
The `ActorContext` `setReceiveTimeout` defines the inactivity timeout after which
|
||||
the sending of a `ReceiveTimeout` message is triggered.
|
||||
When specified, the receive function should be able to handle an `akka.actor.ReceiveTimeout` message.
|
||||
1 millisecond is the minimum supported timeout.
|
||||
|
||||
Please note that the receive timeout might fire and enqueue the *ReceiveTimeout* message right after
|
||||
Please note that the receive timeout might fire and enqueue the `ReceiveTimeout` message right after
|
||||
another message was enqueued; hence it is **not guaranteed** that upon reception of the receive
|
||||
timeout there must have been an idle period beforehand as configured via this method.
|
||||
|
||||
Once set, the receive timeout stays in effect (i.e. continues firing repeatedly after inactivity
|
||||
periods). Pass in *Duration.Undefined* to switch off this feature.
|
||||
periods). Pass in `Duration.Undefined` to switch off this feature.
|
||||
|
||||
@@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #receive-timeout }
|
||||
Scala
|
||||
: @@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #receive-timeout }
|
||||
|
||||
Java
|
||||
: @@snip [ActorDocTest.java]($code$/java/jdocs/actor/ActorDocTest.java) { #receive-timeout }
|
||||
|
||||
Messages marked with `NotInfluenceReceiveTimeout` will not reset the timer. This can be useful when
|
||||
`ReceiveTimeout` should be fired by external inactivity but not influenced by internal activity,
|
||||
|
|
@ -681,7 +914,12 @@ the actor itself or child actors and the system for stopping top level actors. T
|
|||
termination of the actor is performed asynchronously, i.e. `stop` may return before
|
||||
the actor is stopped.
|
||||
|
||||
@@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #stoppingActors-actor }
|
||||
Scala
|
||||
: @@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #stoppingActors-actor }
|
||||
|
||||
Java
|
||||
: @@snip [MyStoppingActor.java]($code$/java/jdocs/actor/MyStoppingActor.java) { #my-stopping-actor }
|
||||
|
||||
|
||||
Processing of the current message, if any, will continue before the actor is stopped,
|
||||
but additional messages in the mailbox will not be processed. By default these
|
||||
|
|
@ -707,7 +945,11 @@ whole system.
|
|||
The `postStop()` hook is invoked after an actor is fully stopped. This
|
||||
enables cleaning up of resources:
|
||||
|
||||
@@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #postStop }
|
||||
Scala
|
||||
: @@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #postStop }
|
||||
|
||||
Java
|
||||
: @@snip [ActorDocTest.java]($code$/java/jdocs/actor/ActorDocTest.java) { #postStop }
|
||||
|
||||
@@@ note
|
||||
|
||||
|
|
@ -727,14 +969,28 @@ stop the actor when the message is processed. `PoisonPill` is enqueued as
|
|||
ordinary messages and will be handled after messages that were already queued
|
||||
in the mailbox.
|
||||
|
||||
Scala
|
||||
: @@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #poison-pill }
|
||||
|
||||
Java
|
||||
: @@snip [ActorDocTest.java]($code$/java/jdocs/actor/ActorDocTest.java) { #poison-pill }
|
||||
|
||||
### Graceful Stop
|
||||
|
||||
`gracefulStop` is useful if you need to wait for termination or compose ordered
|
||||
termination of several actors:
|
||||
|
||||
@@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #gracefulStop }
|
||||
Scala
|
||||
: @@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #gracefulStop }
|
||||
|
||||
@@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #gracefulStop-actor }
|
||||
Java
|
||||
: @@snip [ActorDocTest.java]($code$/java/jdocs/actor/ActorDocTest.java) { #import-gracefulStop #gracefulStop }
|
||||
|
||||
Scala
|
||||
: @@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #gracefulStop-actor }
|
||||
|
||||
Java
|
||||
: @@snip [ActorDocTest.java]($code$/java/jdocs/actor/ActorDocTest.java) { #gracefulStop-actor }
|
||||
|
||||
When `gracefulStop()` returns successfully, the actor’s `postStop()` hook
|
||||
will have been executed: there exists a happens-before edge between the end of
|
||||
|
|
@ -777,9 +1033,13 @@ The phases are ordered with [topological](https://en.wikipedia.org/wiki/Topologi
|
|||
|
||||
Tasks can be added to a phase with:
|
||||
|
||||
@@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #coordinated-shutdown-addTask }
|
||||
Scala
|
||||
: @@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #coordinated-shutdown-addTask }
|
||||
|
||||
The returned `Future[Done]` should be completed when the task is completed. The task name parameter
|
||||
Java
|
||||
: @@snip [ActorDocTest.java]($code$/java/jdocs/actor/ActorDocTest.java) { #coordinated-shutdown-addTask }
|
||||
|
||||
The returned @scala[`Future[Done]`] @java[`CompletionStage<Done>`] should be completed when the task is completed. The task name parameter
|
||||
is only used for debugging/logging.
|
||||
|
||||
Tasks added to the same phase are executed in parallel without any ordering assumptions.
|
||||
|
|
@ -793,12 +1053,16 @@ Tasks should typically be registered as early as possible after system startup.
|
|||
the coordinated shutdown tasks that have been registered will be performed but tasks that are
|
||||
added too late will not be run.
|
||||
|
||||
To start the coordinated shutdown process you can invoke `run` on the `CoordinatedShutdown`
|
||||
To start the coordinated shutdown process you can invoke @scala[`run`] @java[`runAll`] on the `CoordinatedShutdown`
|
||||
extension:
|
||||
|
||||
@@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #coordinated-shutdown-run }
|
||||
Scala
|
||||
: @@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #coordinated-shutdown-run }
|
||||
|
||||
It's safe to call the `run` method multiple times. It will only run once.
|
||||
Java
|
||||
: @@snip [ActorDocTest.java]($code$/java/jdocs/actor/ActorDocTest.java) { #coordinated-shutdown-run }
|
||||
|
||||
It's safe to call the @scala[`run`] @java[`runAll`] method multiple times. It will only run once.
|
||||
|
||||
That also means that the `ActorSystem` will be terminated in the last phase. By default, the
|
||||
JVM is not forcefully stopped (it will be stopped if all non-daemon threads have been terminated).
|
||||
|
|
@ -825,7 +1089,11 @@ If you have application specific JVM shutdown hooks it's recommended that you re
|
|||
`CoordinatedShutdown` so that they are running before Akka internal shutdown hooks, e.g.
|
||||
those shutting down Akka Remoting (Artery).
|
||||
|
||||
@@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #coordinated-shutdown-jvm-hook }
|
||||
Scala
|
||||
: @@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #coordinated-shutdown-jvm-hook }
|
||||
|
||||
Java
|
||||
: @@snip [ActorDocTest.java]($code$/java/jdocs/actor/ActorDocTest.java) { #coordinated-shutdown-jvm-hook }
|
||||
|
||||
For some tests it might be undesired to terminate the `ActorSystem` via `CoordinatedShutdown`.
|
||||
You can disable that by adding the following to the configuration of the `ActorSystem` that is
|
||||
|
|
@ -845,7 +1113,7 @@ akka.cluster.run-coordinated-shutdown-when-down = off
|
|||
|
||||
Akka supports hotswapping the Actor’s message loop (e.g. its implementation) at
|
||||
runtime: invoke the `context.become` method from within the Actor.
|
||||
`become` takes a `PartialFunction[Any, Unit]` that implements the new
|
||||
`become` takes a @scala[`PartialFunction[Any, Unit]`] @java[`PartialFunction<Object, BoxedUnit>`] that implements the new
|
||||
message handler. The hotswapped code is kept in a Stack which can be pushed and
|
||||
popped.
|
||||
|
||||
|
|
@ -857,11 +1125,16 @@ Please note that the actor will revert to its original behavior when restarted b
|
|||
|
||||
To hotswap the Actor behavior using `become`:
|
||||
|
||||
@@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #hot-swap-actor }
|
||||
Scala
|
||||
: @@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #hot-swap-actor }
|
||||
|
||||
Java
|
||||
: @@snip [ActorDocTest.java]($code$/java/jdocs/actor/ActorDocTest.java) { #hot-swap-actor }
|
||||
|
||||
This variant of the `become` method is useful for many different things,
|
||||
such as to implement a Finite State Machine (FSM, for an example see [Dining
|
||||
Hakkers](http://www.lightbend.com/activator/template/akka-sample-fsm-scala)). It will replace the current behavior (i.e. the top of the behavior
|
||||
such as to implement a Finite State Machine (FSM, for an example see @scala[[Dining
|
||||
Hakkers](http://www.lightbend.com/activator/template/akka-sample-fsm-scala)).] @java[[Dining
|
||||
Hakkers](http://www.lightbend.com/activator/template/akka-sample-fsm-java-lambda)).] It will replace the current behavior (i.e. the top of the behavior
|
||||
stack), which means that you do not use `unbecome`, instead always the
|
||||
next behavior is explicitly installed.
|
||||
|
||||
|
|
@ -871,7 +1144,11 @@ of “pop” operations (i.e. `unbecome`) matches the number of “push” ones
|
|||
in the long run, otherwise this amounts to a memory leak (which is why this
|
||||
behavior is not the default).
|
||||
|
||||
@@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #swapper }
|
||||
Scala
|
||||
: @@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #swapper }
|
||||
|
||||
Java
|
||||
: @@snip [ActorDocTest.java]($code$/java/jdocs/actor/ActorDocTest.java) { #swapper }
|
||||
|
||||
### Encoding Scala Actors nested receives without accidentally leaking memory
|
||||
|
||||
|
|
@ -880,27 +1157,43 @@ See this @extref[Unnested receive example](github:akka-docs/src/test/scala/docs/
|
|||
<a id="stash"></a>
|
||||
## Stash
|
||||
|
||||
The *Stash* trait enables an actor to temporarily stash away messages
|
||||
The @scala[`Stash` trait] @java[`AbstractActorWithStash` class] enables an actor to temporarily stash away messages
|
||||
that can not or should not be handled using the actor's current
|
||||
behavior. Upon changing the actor's message handler, i.e., right
|
||||
before invoking `context.become` or `context.unbecome`, all
|
||||
before invoking @scala[`context.become` or `context.unbecome`] @java[`getContext().become()` or `getContext().unbecome()`], all
|
||||
stashed messages can be "unstashed", thereby prepending them to the actor's
|
||||
mailbox. This way, the stashed messages can be processed in the same
|
||||
order as they have been received originally.
|
||||
order as they have been received originally. @java[An actor that extends
|
||||
`AbstractActorWithStash` will automatically get a deque-based mailbox.]
|
||||
|
||||
@@@ note
|
||||
@@@ note { .group-scala }
|
||||
|
||||
The trait `Stash` extends the marker trait
|
||||
`RequiresMessageQueue[DequeBasedMessageQueueSemantics]` which
|
||||
requests the system to automatically choose a deque based
|
||||
mailbox implementation for the actor. If you want more control over the
|
||||
mailbox implementation for the actor. If you want more
|
||||
control over the
|
||||
mailbox, see the documentation on mailboxes: @ref:[Mailboxes](mailboxes.md).
|
||||
|
||||
@@@
|
||||
|
||||
Here is an example of the `Stash` in action:
|
||||
@@@ note { .group-java }
|
||||
|
||||
@@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #stash }
|
||||
The abstract class `AbstractActorWithStash` implements the marker
|
||||
interface `RequiresMessageQueue<DequeBasedMessageQueueSemantics>`
|
||||
which requests the system to automatically choose a deque based
|
||||
mailbox implementation for the actor. If you want more
|
||||
control over the mailbox, see the documentation on mailboxes: @ref:[Mailboxes](mailboxes.md).
|
||||
|
||||
@@@
|
||||
|
||||
Here is an example of the @scala[`Stash`] @java[`AbstractActorWithStash` class] in action:
|
||||
|
||||
Scala
|
||||
: @@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #stash }
|
||||
|
||||
Java
|
||||
: @@snip [ActorDocTest.java]($code$/java/jdocs/actor/ActorDocTest.java) { #stash }
|
||||
|
||||
Invoking `stash()` adds the current message (the message that the
|
||||
actor received last) to the actor's stash. It is typically invoked
|
||||
|
|
@ -924,7 +1217,7 @@ The stash is backed by a `scala.collection.immutable.Vector`. As a
|
|||
result, even a very large number of messages may be stashed without a
|
||||
major impact on performance.
|
||||
|
||||
@@@ warning
|
||||
@@@ warning { .group-scala }
|
||||
|
||||
Note that the `Stash` trait must be mixed into (a subclass of) the
|
||||
`Actor` trait before any trait/class that overrides the `preRestart`
|
||||
|
|
@ -935,14 +1228,14 @@ callback. This means it's not possible to write
|
|||
|
||||
Note that the stash is part of the ephemeral actor state, unlike the
|
||||
mailbox. Therefore, it should be managed like other parts of the
|
||||
actor's state which have the same property. The `Stash` trait’s
|
||||
actor's state which have the same property. The @scala[`Stash` trait’s] @java[`AbstractActorWithStash`]
|
||||
implementation of `preRestart` will call `unstashAll()`, which is
|
||||
usually the desired behavior.
|
||||
|
||||
@@@ note
|
||||
|
||||
If you want to enforce that your actor can only work with an unbounded stash,
|
||||
then you should use the `UnboundedStash` trait instead.
|
||||
then you should use the @scala[`UnboundedStash` trait] @java[`AbstractActorWithUnboundedStash` class] instead.
|
||||
|
||||
@@@
|
||||
|
||||
|
|
@ -957,10 +1250,11 @@ See @ref:[What Supervision Means](general/supervision.md#supervision-directives)
|
|||
|
||||
Use `Kill` like this:
|
||||
|
||||
```scala
|
||||
// kill the 'victim' actor
|
||||
victim ! Kill
|
||||
```
|
||||
Scala
|
||||
: @@snip [ActorDocSpec.scala]($code$/scala/docs/actor/ActorDocSpec.scala) { #kill }
|
||||
|
||||
Java
|
||||
: @@snip [ActorDocTest.java]($code$/java/jdocs/actor/ActorDocTest.java) { #kill }
|
||||
|
||||
## Actors and exceptions
|
||||
|
||||
|
|
@ -990,6 +1284,8 @@ supervision process is started (see @ref:[supervision](general/supervision.md)).
|
|||
supervisor’s decision the actor is resumed (as if nothing happened), restarted
|
||||
(wiping out its internal state and starting from scratch) or terminated.
|
||||
|
||||
@@@ div { .group-scala }
|
||||
|
||||
## Extending Actors using PartialFunction chaining
|
||||
|
||||
Sometimes it can be useful to share common behavior among a few actors, or compose one actor's behavior from multiple smaller functions.
|
||||
|
|
@ -1005,6 +1301,8 @@ traits and implementing the actor's `receive` as combination of these partial fu
|
|||
|
||||
Instead of inheritance the same pattern can be applied via composition - one would simply compose the receive method using partial functions from delegates.
|
||||
|
||||
@@@
|
||||
|
||||
## Initialization patterns
|
||||
|
||||
The rich lifecycle hooks of Actors provide a useful toolkit to implement various initialization patterns. During the
|
||||
|
|
@ -1034,8 +1332,13 @@ this behavior, and ensure that there is only one call to `preStart()`.
|
|||
One useful usage of this pattern is to disable creation of new `ActorRefs` for children during restarts. This can be
|
||||
achieved by overriding `preRestart()`:
|
||||
|
||||
@@snip [InitializationDocSpec.scala]($code$/scala/docs/actor/InitializationDocSpec.scala) { #preStartInit }
|
||||
Scala
|
||||
: @@snip [InitializationDocSpec.scala]($code$/scala/docs/actor/InitializationDocSpec.scala) { #preStartInit }
|
||||
|
||||
Java
|
||||
: @@snip [InitializationDocTest.java]($code$/java/jdocs/actor/InitializationDocTest.java) { #preStartInit }
|
||||
|
||||
|
||||
Please note, that the child actors are *still restarted*, but no new `ActorRef` is created. One can recursively apply
|
||||
the same principles for the children, ensuring that their `preStart()` method is called only at the creation of their
|
||||
refs.
|
||||
|
|
@ -1049,7 +1352,11 @@ for example in the presence of circular dependencies. In this case the actor sho
|
|||
and use `become()` or a finite state-machine state transition to encode the initialized and uninitialized states
|
||||
of the actor.
|
||||
|
||||
@@snip [InitializationDocSpec.scala]($code$/scala/docs/actor/InitializationDocSpec.scala) { #messageInit }
|
||||
Scala
|
||||
: @@snip [InitializationDocSpec.scala]($code$/scala/docs/actor/InitializationDocSpec.scala) { #messageInit }
|
||||
|
||||
Java
|
||||
: @@snip [InitializationDocTest.java]($code$/java/jdocs/actor/InitializationDocTest.java) { #messageInit }
|
||||
|
||||
If the actor may receive messages before it has been initialized, a useful tool can be the `Stash` to save messages
|
||||
until the initialization finishes, and replaying them after the actor became initialized.
|
||||
|
|
|
|||
37
akka-docs/src/main/paradox/scala/scala-compat.md
Normal file
37
akka-docs/src/main/paradox/scala/scala-compat.md
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
# Java 8 and Scala Compatibility
|
||||
|
||||
Akka requires that you have [Java 8](http://www.oracle.com/technetwork/java/javase/downloads/index.html) or
|
||||
later installed on your machine.
|
||||
|
||||
## Java 8 types
|
||||
|
||||
Starting with Akka 2.4.2 we have begun to introduce Java 8 types (most
|
||||
prominently `java.util.concurrent.CompletionStage` and
|
||||
`java.util.Optional`) where that was possible without breaking binary or
|
||||
source compatibility. Where this was not possible (for example in the return
|
||||
type of `ActorSystem.terminate()`) please refer to the
|
||||
`scala-java8-compat` library that allows easy conversion between the Scala
|
||||
and Java counterparts. The artifact can be included in Maven builds using:
|
||||
|
||||
```
|
||||
<dependency>
|
||||
<groupId>org.scala-lang.modules</groupId>
|
||||
<artifactId>scala-java8-compat_2.11</artifactId>
|
||||
<version>0.7.0</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
We will only be able to seamlessly integrate all functional interfaces once
|
||||
we can rely on Scala 2.12 to provide full interoperability—this will mean that
|
||||
Scala users can directly implement Java Functional Interfaces using lambda syntax
|
||||
as well as that Java users can directly implement Scala functions using lambda
|
||||
syntax.
|
||||
|
||||
## Do not use -optimize Scala compiler flag
|
||||
|
||||
@@@ warning
|
||||
|
||||
Akka has not been compiled or tested with -optimize Scala compiler flag.
|
||||
Strange behavior has been reported by users that have tried it.
|
||||
|
||||
@@@
|
||||
|
|
@ -310,6 +310,13 @@ class Ponger(pinger: ActorRef) extends Actor {
|
|||
|
||||
//#fiddle_code
|
||||
|
||||
//#immutable-message-definition
|
||||
case class User(name: String)
|
||||
|
||||
// define the case class
|
||||
case class Register(user: User)
|
||||
//#immutable-message-definition
|
||||
|
||||
class ActorDocSpec extends AkkaSpec("""
|
||||
akka.loglevel = INFO
|
||||
akka.loggers = []
|
||||
|
|
@ -381,6 +388,23 @@ class ActorDocSpec extends AkkaSpec("""
|
|||
system.terminate()
|
||||
}
|
||||
|
||||
"instantiates a case class" in {
|
||||
//#immutable-message-instantiation
|
||||
val user = User("Mike")
|
||||
// create a new case class message
|
||||
val message = Register(user)
|
||||
//#immutable-message-instantiation
|
||||
}
|
||||
|
||||
"use poison pill" in {
|
||||
val victim = system.actorOf(Props[MyActor])
|
||||
//#poison-pill
|
||||
watch(victim)
|
||||
victim ! PoisonPill
|
||||
//#poison-pill
|
||||
expectTerminated(victim)
|
||||
}
|
||||
|
||||
"creating a Props config" in {
|
||||
//#creating-props
|
||||
import akka.actor.Props
|
||||
|
|
@ -562,10 +586,12 @@ class ActorDocSpec extends AkkaSpec("""
|
|||
}
|
||||
}
|
||||
//#watch
|
||||
val a = system.actorOf(Props(classOf[WatchActor], this))
|
||||
val victim = system.actorOf(Props(classOf[WatchActor], this))
|
||||
implicit val sender = testActor
|
||||
a ! "kill"
|
||||
//#kill
|
||||
victim ! "kill"
|
||||
expectMsg("finished")
|
||||
//#kill
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue