Improve doc language (#30786)
This commit is contained in:
parent
659eb40146
commit
6f30c6fc08
2 changed files with 148 additions and 156 deletions
|
|
@ -27,7 +27,7 @@ The [Actor Model](https://en.wikipedia.org/wiki/Actor_model) provides a higher l
|
|||
and distributed systems. It alleviates the developer from having to deal with
|
||||
explicit locking and thread management, making it easier to write correct
|
||||
concurrent and parallel systems. Actors were defined in the 1973 paper by Carl
|
||||
Hewitt but have been popularized by the Erlang language, and used for example at
|
||||
Hewitt but have been popularized by the Erlang language and used for example at
|
||||
Ericsson with great success to build highly concurrent and reliable telecom
|
||||
systems.
|
||||
|
||||
|
|
@ -52,7 +52,7 @@ as well as @ref:[Actor References, Paths and Addresses](general/addressing.md).
|
|||
|
||||
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
|
||||
statements (which has the type `PartialFunction[Any, Unit]`) that define
|
||||
which messages your Actor can handle, using standard Scala pattern matching,
|
||||
along with the implementation of how the messages should be processed.
|
||||
|
||||
|
|
@ -61,12 +61,10 @@ 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 `createReceive` method.
|
||||
the “initial behavior” in the `createReceive` method.
|
||||
|
||||
`createReceive` method has no arguments and returns `AbstractActor.Receive`. It
|
||||
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`. This build has convenient factory in `AbstractActor` called `receiveBuilder`.
|
||||
The `createReceive` method has no arguments and returns `AbstractActor.Receive`. It 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`. This build has a convenient factory in `AbstractActor` called `receiveBuilder`.
|
||||
|
||||
@@@
|
||||
|
||||
|
|
@ -78,8 +76,7 @@ Scala
|
|||
Java
|
||||
: @@snip [MyActor.java](/akka-docs/src/test/java/jdocs/actor/MyActor.java) { #imports #my-actor }
|
||||
|
||||
Please note that the Akka Actor @scala[`receive`] message loop is exhaustive, which
|
||||
is different compared to Erlang and the late Scala Actors. This means that you
|
||||
Please note that the Akka Actor @scala[`receive`] message loop is exhaustive, which is different compared to Erlang and the late Scala Actors. This means that you
|
||||
need to provide a pattern match for all messages that it can accept and if you
|
||||
want to be able to handle unknown messages then you need to have a default case
|
||||
as in the example above. Otherwise an `akka.actor.UnhandledMessage(message,
|
||||
|
|
@ -91,8 +88,8 @@ the actor shall reply to the received message then this must be done explicitly
|
|||
as explained below.
|
||||
|
||||
The result of the @scala[`receive` method is a partial function object, which is]
|
||||
@java[`createReceive` method is `AbstractActor.Receive` which is a wrapper around partial
|
||||
scala function object. It is] stored within the actor as its “initial behavior”,
|
||||
@java[`createReceive` method is `AbstractActor.Receive` which is a wrapper around partial
|
||||
scala function object. It is] stored within the actor as its “initial behavior”,
|
||||
see @ref:[Become/Unbecome](#become-unbecome) for
|
||||
further information on changing the behavior of an actor after its
|
||||
construction.
|
||||
|
|
@ -109,7 +106,7 @@ construction.
|
|||
|
||||
`Props` is a configuration class to specify options for the creation
|
||||
of actors, think of it as an immutable and thus freely shareable recipe for
|
||||
creating an actor including associated deployment information (e.g. which
|
||||
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.
|
||||
|
||||
|
|
@ -144,16 +141,16 @@ Scala
|
|||
Java
|
||||
: @@snip [ActorDocTest.java](/akka-docs/src/test/java/jdocs/actor/ActorDocTest.java) { #creating-props-deprecated }
|
||||
|
||||
This method is not recommended to be used within another actor because it
|
||||
This method is not recommended being used within another actor because it
|
||||
encourages to close over the enclosing scope, resulting in non-serializable
|
||||
`Props` and possibly race conditions (breaking the actor encapsulation).
|
||||
On the other hand using this variant in a `Props` factory in
|
||||
On the other hand, using this variant in a `Props` factory in
|
||||
the actor’s companion object as documented under “Recommended Practices” below
|
||||
is completely fine.
|
||||
|
||||
There were two use-cases for these methods: passing constructor arguments to
|
||||
the actor—which is solved by the newly introduced
|
||||
@scala[`Props.apply(clazz, args)`] @java[`Props.create(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`
|
||||
|
|
@ -172,17 +169,17 @@ encapsulation. Never pass an actor’s `this` reference into `Props`!
|
|||
|
||||
There are two edge cases in actor creation with `Props`:
|
||||
|
||||
* An actor with `AnyVal` arguments.
|
||||
* An actor with `AnyVal` arguments.
|
||||
|
||||
@@snip [PropsEdgeCaseSpec.scala](/akka-docs/src/test/scala/docs/actor/PropsEdgeCaseSpec.scala) { #props-edge-cases-value-class }
|
||||
|
||||
@@snip [PropsEdgeCaseSpec.scala](/akka-docs/src/test/scala/docs/actor/PropsEdgeCaseSpec.scala) { #props-edge-cases-value-class-example }
|
||||
|
||||
* An actor with default constructor values.
|
||||
* An actor with default constructor values.
|
||||
|
||||
@@snip [PropsEdgeCaseSpec.scala](/akka-docs/src/test/scala/docs/actor/PropsEdgeCaseSpec.scala) { #props-edge-cases-default-values }
|
||||
|
||||
In both cases an `IllegalArgumentException` will be thrown stating
|
||||
In both cases, an `IllegalArgumentException` will be thrown stating
|
||||
no matching constructor could be found.
|
||||
|
||||
The next section explains the recommended ways to create `Actor` props in a way,
|
||||
|
|
@ -193,11 +190,11 @@ which simultaneously safe-guards against these edge cases.
|
|||
#### Recommended Practices
|
||||
|
||||
It is a good idea to provide @scala[factory methods on the companion object of each
|
||||
`Actor`] @java[static factory methods for each `Actor`] which help keeping the creation of
|
||||
`Actor`] @java[static factory methods for 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 @scala[`Props.apply(...)` method which takes a by-name
|
||||
argument, since within a companion object] @java[ `Props.create(...)` method which takes
|
||||
arguments as constructor parameters, since within static method]
|
||||
argument, since within a companion object] @java[ `Props.create(...)` method which takes
|
||||
arguments as constructor parameters, since within static method]
|
||||
the given code block will not retain a reference to its enclosing scope:
|
||||
|
||||
Scala
|
||||
|
|
@ -230,7 +227,7 @@ Java
|
|||
: @@snip [ActorDocTest.java](/akka-docs/src/test/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
|
||||
actor system’s provided guardian actor while using an actor’s context will
|
||||
create a child actor.
|
||||
|
||||
Scala
|
||||
|
|
@ -248,13 +245,13 @@ handle to the actor instance and the only way to interact with it. The
|
|||
`ActorRef` is immutable and has a one to one relationship with the Actor
|
||||
it represents. The `ActorRef` is also serializable and network-aware.
|
||||
This means that you can serialize it, send it over the wire and use it on a
|
||||
remote host and it will still be representing the same Actor on the original
|
||||
remote host, and it will still be representing the same Actor on the original
|
||||
node, across the network.
|
||||
|
||||
The name parameter is optional, but you should preferably name your actors,
|
||||
since that is used in log messages and for identifying actors. The name must
|
||||
not be empty or start with `$`, but it may contain URL encoded characters
|
||||
(eg. `%20` for a blank space). If the given name is already in use by
|
||||
(eg., `%20` for a blank space). If the given name is already in use by
|
||||
another child to the same parent an `InvalidActorNameException` is thrown.
|
||||
|
||||
Actors are automatically started asynchronously when created.
|
||||
|
|
@ -265,7 +262,7 @@ Actors are automatically started asynchronously when created.
|
|||
|
||||
The recommended way to instantiate actor props uses reflection at runtime
|
||||
to determine the correct actor constructor to be invoked and due to technical
|
||||
limitations is not supported when said constructor takes arguments that are
|
||||
limitations it is not supported when said constructor takes arguments that are
|
||||
value classes.
|
||||
In these cases you should either unpack the arguments or create the props by
|
||||
calling the constructor manually:
|
||||
|
|
@ -320,22 +317,22 @@ actual Debug messages).
|
|||
|
||||
In addition, it offers:
|
||||
|
||||
* @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
|
||||
* @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
|
||||
messages (albeit outside of the normal behavior), all values and variables
|
||||
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).
|
||||
This strategy is typically declared inside the actor 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
|
||||
messages (albeit outside the normal behavior), all values and variables
|
||||
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).
|
||||
|
||||
* @scala[`context`] @java[`getContext()`] 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
|
||||
|
|
@ -358,7 +355,7 @@ Scala
|
|||
: @@snip [Actor.scala](/akka-actor/src/main/scala/akka/actor/Actor.scala) { #lifecycle-hooks }
|
||||
|
||||
Java
|
||||
: @@snip [ActorDocTest.java](/akka-docs/src/test/java/jdocs/actor/ActorDocTest.java) { #lifecycle-callbacks }
|
||||
: @@snip [ActorDocTest.java](/akka-docs/src/test/java/jdocs/actor/ActorDocTest.java) { #lifecycle-callbacks }
|
||||
|
||||
The implementations shown above are the defaults provided by the @scala[`Actor` trait.] @java[`AbstractActor` class.]
|
||||
|
||||
|
|
@ -366,31 +363,31 @@ The implementations shown above are the defaults provided by the @scala[`Actor`
|
|||
|
||||

|
||||
|
||||
A path in an actor system represents a "place" which might be occupied
|
||||
A path in an actor system represents a "place" that might be occupied
|
||||
by a living actor. Initially (apart from system initialized actors) a path is
|
||||
empty. When `actorOf()` is called it assigns an *incarnation* of the actor
|
||||
described by the passed `Props` to the given path. An actor incarnation is
|
||||
identified by the path *and a UID*.
|
||||
identified by the path *and a UID*.
|
||||
|
||||
It is worth noting about the difference between:
|
||||
|
||||
* restart
|
||||
* stop, followed by re-creation of actor
|
||||
* restart
|
||||
* stop, followed by a re-creation of the actor
|
||||
|
||||
as explained below.
|
||||
|
||||
A restart only swaps the `Actor`
|
||||
instance defined by the `Props` but the incarnation and hence the UID remains
|
||||
the same.
|
||||
As long as the incarnation is same, you can keep using the same `ActorRef`.
|
||||
As long as the incarnation is the same, you can keep using the same `ActorRef`.
|
||||
Restart is handled by the @ref:[Supervision Strategy](fault-tolerance.md#creating-a-supervisor-strategy) of actor's parent actor,
|
||||
and there is more discussion about @ref:[what restart means](general/supervision.md#supervision-restart).
|
||||
|
||||
The lifecycle of an incarnation ends when the actor is stopped. At
|
||||
that point the appropriate lifecycle events are called and watching actors
|
||||
that point, the appropriate lifecycle events are called and watching actors
|
||||
are notified of the termination. After the incarnation is stopped, the path can
|
||||
be reused again by creating an actor with `actorOf()`. In this case the
|
||||
name of the new incarnation will be the same as the previous one but the
|
||||
be reused again by creating an actor with `actorOf()`. In this case, the
|
||||
name of the new incarnation will be the same as the previous one, but the
|
||||
UIDs will differ. An actor can be stopped by the actor itself, another actor
|
||||
or the `ActorSystem` (see @ref:[Stopping actors](#stopping-actors)).
|
||||
|
||||
|
|
@ -404,8 +401,8 @@ stop all the child Actors that this parent has created.
|
|||
@@@
|
||||
|
||||
An `ActorRef` always represents an incarnation (path and UID) not just a
|
||||
given path. Therefore if an actor is stopped and a new one with the same
|
||||
name is created an `ActorRef` of the old incarnation will not point
|
||||
given path. Therefore, if an actor is stopped, and a new one with the same
|
||||
name is created then an `ActorRef` of the old incarnation will not point
|
||||
to the new one.
|
||||
|
||||
`ActorSelection` on the other hand points to the path (or multiple paths
|
||||
|
|
@ -421,8 +418,8 @@ method of the `ActorSelection`, which returns a `Future` of the matching
|
|||
<a id="deathwatch"></a>
|
||||
### Lifecycle Monitoring aka DeathWatch
|
||||
|
||||
In order to be notified when another actor terminates (i.e. stops permanently,
|
||||
not temporary failure and restart), an actor may register itself for reception
|
||||
To be notified when another actor terminates (i.e., stops permanently,
|
||||
not a temporary failure and restart), an actor may register itself for reception
|
||||
of the `Terminated` message dispatched by the other actor upon
|
||||
termination (see @ref:[Stopping Actors](#stopping-actors)). This service is provided by the
|
||||
`DeathWatch` component of the actor system.
|
||||
|
|
@ -436,7 +433,7 @@ Java
|
|||
: @@snip [ActorDocTest.java](/akka-docs/src/test/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.
|
||||
independently of the order in which registration and termination occur.
|
||||
In particular, the watching actor will receive a `Terminated` message even if the
|
||||
watched actor has already been terminated at the time of registration.
|
||||
|
||||
|
|
@ -444,7 +441,7 @@ Registering multiple times does not necessarily lead to multiple messages being
|
|||
generated, but there is no guarantee that only exactly one such message is
|
||||
received: if termination of the watched actor has generated and queued the
|
||||
message, and another registration is done before this message has been
|
||||
processed, then a second message will be queued, because registering for
|
||||
processed, then a second message will be queued because registering for
|
||||
monitoring of an already terminated actor leads to the immediate generation of
|
||||
the `Terminated` message.
|
||||
|
||||
|
|
@ -463,10 +460,10 @@ Scala
|
|||
Java
|
||||
: @@snip [ActorDocTest.java](/akka-docs/src/test/java/jdocs/actor/ActorDocTest.java) { #preStart }
|
||||
|
||||
This method is called when the actor is first created. During restarts it is
|
||||
This method is called when the actor is first created. During restarts, it is
|
||||
called by the default implementation of `postRestart`, which means that
|
||||
by overriding that method you can choose whether the initialization code in
|
||||
this method is called only exactly once for this actor or for every restart.
|
||||
this method is called only exactly once for this actor or every restart.
|
||||
Initialization code which is part of the actor’s constructor will always be
|
||||
called when an instance of the actor class is created, which happens at every
|
||||
restart.
|
||||
|
|
@ -474,29 +471,29 @@ restart.
|
|||
<a id="restart-hook"></a>
|
||||
### Restart Hooks
|
||||
|
||||
All actors are supervised, i.e. linked to another actor with a fault
|
||||
All actors are supervised, i.e., linked to another actor with a fault
|
||||
handling strategy. Actors may be restarted in case an exception is thrown while
|
||||
processing a message (see @ref:[supervision](general/supervision.md)). This restart involves the hooks
|
||||
mentioned above:
|
||||
|
||||
1. The old actor is informed by calling `preRestart` with the exception
|
||||
which caused the restart and the message which triggered that exception; the
|
||||
latter may be `None` if the restart was not caused by processing a
|
||||
message, e.g. when a supervisor does not trap the exception and is restarted
|
||||
in turn by its supervisor, or if an actor is restarted due to a sibling’s
|
||||
failure. If the message is available, then that message’s sender is also
|
||||
accessible in the usual way (i.e. by calling `sender`).
|
||||
This method is the best place for cleaning up, preparing hand-over to the
|
||||
fresh actor instance, etc. By default it stops all children and calls
|
||||
`postStop`.
|
||||
2. The initial factory from the `actorOf` call is used
|
||||
to produce the fresh instance.
|
||||
3. The new actor’s `postRestart` method is invoked with the exception
|
||||
which caused the restart. By default the `preStart`
|
||||
is called, just as in the normal start-up case.
|
||||
1. The old actor is informed by calling `preRestart` with the exception
|
||||
which caused the restart, and the message which triggered that exception; the
|
||||
latter may be `None` if the restart was not caused by processing a
|
||||
message, e.g. when a supervisor does not trap the exception and is restarted
|
||||
in turn by its supervisor, or if an actor is restarted due to a sibling’s
|
||||
failure. If the message is available, then that message’s sender is also
|
||||
accessible in the usual way (i.e. by calling `sender`).
|
||||
This method is the best place for cleaning up, preparing hand-over to the
|
||||
fresh actor instance, etc. By default, it stops all children and calls
|
||||
`postStop`.
|
||||
2. The initial factory from the `actorOf` call is used
|
||||
to produce the fresh instance.
|
||||
3. The new actor’s `postRestart` method is invoked with the exception
|
||||
which caused the restart. By default the `preStart`
|
||||
is called, just as in the normal start-up case.
|
||||
|
||||
An actor restart replaces only the actual actor object; the contents of the
|
||||
mailbox is unaffected by the restart, so processing of messages will resume
|
||||
mailbox are unaffected by the restart, so the processing of messages will resume
|
||||
after the `postRestart` hook returns. The message
|
||||
that triggered the exception will not be received again. Any message
|
||||
sent to an actor while it is being restarted will be queued to its mailbox as
|
||||
|
|
@ -543,10 +540,10 @@ Java
|
|||
It is always preferable to communicate with other Actors using their ActorRef
|
||||
instead of relying upon ActorSelection. Exceptions are
|
||||
|
||||
* sending messages using the @ref:[At-Least-Once Delivery](persistence.md#at-least-once-delivery) facility
|
||||
* initiating first contact with a remote system
|
||||
* sending messages using the @ref:[At-Least-Once Delivery](persistence.md#at-least-once-delivery) facility
|
||||
* initiating the first contact with a remote system
|
||||
|
||||
In all other cases ActorRefs can be provided during Actor creation or
|
||||
In all other cases, ActorRefs can be provided during Actor creation or
|
||||
initialization, passing them from parent to child or introducing Actors by
|
||||
sending their ActorRefs to other Actors within messages.
|
||||
|
||||
|
|
@ -577,7 +574,7 @@ 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 @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
|
||||
understand and automatically reply to with an `ActorIdentity` message
|
||||
containing the `ActorRef`. This message is handled specially by the
|
||||
actors which are traversed in the sense that if a concrete name lookup fails
|
||||
(i.e. a non-wildcard path element does not correspond to a live actor) then a
|
||||
|
|
@ -613,7 +610,7 @@ An example demonstrating actor look-up is given in @ref:[Remoting Sample](remoti
|
|||
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
|
||||
use Scala case classes that are immutable (if you don’t explicitly expose the
|
||||
state) and works great with pattern matching at the receiver side.]
|
||||
|
||||
@@@
|
||||
|
|
@ -631,10 +628,10 @@ Java
|
|||
|
||||
Messages are sent to an Actor through one of the following methods.
|
||||
|
||||
* @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 @scala[`Future`]@java[`CompletionStage`]
|
||||
representing a possible reply. @scala[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 @scala[`Future`]@java[`CompletionStage`]
|
||||
representing a possible reply. @scala[Also known as `ask`.]
|
||||
|
||||
Message ordering is guaranteed on a per-sender basis.
|
||||
|
||||
|
|
@ -651,7 +648,7 @@ remoting. So always prefer `tell` for performance, and only `ask` if you must.
|
|||
|
||||
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.
|
||||
to your message since the sender reference is sent along with the message.
|
||||
|
||||
@@@
|
||||
|
||||
|
|
@ -688,7 +685,7 @@ 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..
|
||||
the ask-pattern described next.
|
||||
|
||||
@@@
|
||||
|
||||
|
|
@ -722,10 +719,10 @@ which it is destroyed in order not to leak resources; see more below.
|
|||
@@@ warning
|
||||
|
||||
To complete the @scala[`Future`]@java[`CompletionStage`] with an exception you need to send an `akka.actor.Status.Failure` message to the sender.
|
||||
This is *not done automatically* when an actor throws an exception while processing a message.
|
||||
This is *not done automatically* when an actor throws an exception while processing a message.
|
||||
|
||||
@scala[Please note that Scala's `Try` sub types `scala.util.Failure` and `scala.util.Success` are not treated
|
||||
specially, and would complete the ask @scala[`Future`]@java[`CompletionStage`] with the given value - only the `akka.actor.Status` messages
|
||||
especially, and would complete the ask @scala[`Future`]@java[`CompletionStage`] with the given value - only the `akka.actor.Status` messages
|
||||
are treated specially by the ask pattern.]
|
||||
|
||||
@@@
|
||||
|
|
@ -763,7 +760,7 @@ 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
|
||||
encapsulation and may introduce synchronization bugs and race conditions because
|
||||
the callback will be scheduled concurrently to the enclosing actor. Unfortunately
|
||||
the callback will be scheduled concurrently to the enclosing actor. Unfortunately,
|
||||
there is not yet a way to detect these illegal accesses at compile time.
|
||||
See also: @ref:[Actors and shared mutable state](general/jmm.md#jmm-shared-state)
|
||||
|
||||
|
|
@ -825,24 +822,24 @@ trail, you can split the creation of the builder into multiple statements as in
|
|||
|
||||
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:
|
||||
with lots of code in each lambda. A well-structured actor can look like this:
|
||||
|
||||
@@snip [ActorDocTest.java](/akka-docs/src/test/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
|
||||
* 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
|
||||
The `Receive` can be implemented in other ways than using the `ReceiveBuilder` since in the
|
||||
end, it 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 [Vavr Pattern Matching DSL](https://www.vavr.io/vavr-docs/#_pattern_matching). See the [Akka Vavr sample project](https://github.com/akka/akka-samples/tree/2.5/akka-sample-vavr) for more details.
|
||||
|
||||
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
|
||||
actors you can consider implementing it at a 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
|
||||
|
|
@ -859,7 +856,7 @@ untyped version. When extending `UntypedAbstractActor` each message is received
|
|||
If you want to have a handle for replying to a message, you can use
|
||||
@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
|
||||
for replying later, or passing it 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.
|
||||
|
||||
|
|
@ -916,15 +913,15 @@ Each timer has a key and can be replaced or cancelled. It's guaranteed that a me
|
|||
previous incarnation of the timer with the same key is not received, even though it might already
|
||||
be enqueued in the mailbox when it was cancelled or the new timer was started.
|
||||
|
||||
The timers are bound to the lifecycle of the actor that owns it, and thus are cancelled
|
||||
automatically when it is restarted or stopped. Note that the `TimerScheduler` is not thread-safe,
|
||||
The timers are bound to the lifecycle of the actor that owns it and thus are cancelled
|
||||
automatically when it is restarted or stopped. Note that the `TimerScheduler` is not thread-safe,
|
||||
i.e. it must only be used within the actor that owns it.
|
||||
|
||||
## Stopping actors
|
||||
|
||||
Actors are stopped by invoking the `stop` method of a `ActorRefFactory`,
|
||||
i.e. `ActorContext` or `ActorSystem`. Typically the context is used for stopping
|
||||
the actor itself or child actors and the system for stopping top level actors. The actual
|
||||
the actor itself or child actors and the system for stopping top-level actors. The actual
|
||||
termination of the actor is performed asynchronously, i.e. `stop` may return before
|
||||
the actor is stopped.
|
||||
|
||||
|
|
@ -936,7 +933,7 @@ Java
|
|||
|
||||
|
||||
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
|
||||
but additional messages in the mailbox will not be processed. By default, these
|
||||
messages are sent to the `deadLetters` of the `ActorSystem`, but that
|
||||
depends on the mailbox implementation.
|
||||
|
||||
|
|
@ -948,7 +945,7 @@ publishing `Terminated` on the @ref:[DeathWatch](#deathwatch), telling
|
|||
its supervisor). This procedure ensures that actor system sub-trees terminate
|
||||
in an orderly fashion, propagating the stop command to the leaves and
|
||||
collecting their confirmation back to the stopped supervisor. If one of the
|
||||
actors does not respond (i.e. processing a message for extended periods of time
|
||||
actors do not respond (i.e. processing a message for extended periods of time
|
||||
and therefore not receiving the stop command), this whole process will be
|
||||
stuck.
|
||||
|
||||
|
|
@ -992,8 +989,7 @@ Java
|
|||
<a id="killing-actors"></a>
|
||||
### Killing an Actor
|
||||
|
||||
You can also "kill" an actor by sending a `Kill` message. Unlike `PoisonPill` this will cause
|
||||
the actor to throw a `ActorKilledException`, triggering a failure. The actor will
|
||||
You can also "kill" an actor by sending a `Kill` message. Unlike `PoisonPill` this will cause the actor to throw a `ActorKilledException`, triggering a failure. The actor will
|
||||
suspend operation and its supervisor will be asked how to handle the failure,
|
||||
which may mean resuming the actor, restarting it or terminating it completely.
|
||||
See @ref:[What Supervision Means](general/supervision.md#supervision-directives) for more information.
|
||||
|
|
@ -1006,8 +1002,8 @@ Scala
|
|||
Java
|
||||
: @@snip [ActorDocTest.java](/akka-docs/src/test/java/jdocs/actor/ActorDocTest.java) { #kill }
|
||||
|
||||
In general though it is not recommended to overly rely on either `PoisonPill` or `Kill` in
|
||||
designing your actor interactions, as often times a protocol-level message like `PleaseCleanupAndStop`
|
||||
In general, it is not recommended to overly rely on either `PoisonPill` or `Kill` in
|
||||
designing your actor interactions, as often a protocol-level message like `PleaseCleanupAndStop`
|
||||
which the actor knows how to handle is encouraged. The messages are there for being able to stop actors
|
||||
over which design you do not have control over.
|
||||
|
||||
|
|
@ -1026,7 +1022,7 @@ When `gracefulStop()` returns successfully, the actor’s `postStop()` hook
|
|||
will have been executed: there exists a happens-before edge between the end of
|
||||
`postStop()` and the return of `gracefulStop()`.
|
||||
|
||||
In the above example a custom `Manager.Shutdown` message is sent to the target
|
||||
In the above example, a custom `Manager.Shutdown` message is sent to the target
|
||||
actor to initiate the process of stopping the actor. You can use `PoisonPill` for
|
||||
this, but then you have limited possibilities to perform interactions with other actors
|
||||
before stopping the target actor. Simple cleanup tasks can be handled in `postStop`.
|
||||
|
|
@ -1034,9 +1030,9 @@ before stopping the target actor. Simple cleanup tasks can be handled in `postSt
|
|||
@@@ warning
|
||||
|
||||
Keep in mind that an actor stopping and its name being deregistered are
|
||||
separate events which happen asynchronously from each other. Therefore it may
|
||||
separate events that happen asynchronously from each other. Therefore it may
|
||||
be that you will find the name still in use after `gracefulStop()`
|
||||
returned. In order to guarantee proper deregistration, only reuse names from
|
||||
returned. To guarantee proper deregistration, only reuse names from
|
||||
within a supervisor you control and only in response to a `Terminated`
|
||||
message, i.e. not for top-level actors.
|
||||
|
||||
|
|
@ -1050,7 +1046,7 @@ message, i.e. not for top-level actors.
|
|||
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 @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
|
||||
message handler. The hotswapped code is kept in a Stack that can be pushed and
|
||||
popped.
|
||||
|
||||
@@@ warning
|
||||
|
|
@ -1073,7 +1069,7 @@ stack), which means that you do not use `unbecome`, instead always the
|
|||
next behavior is explicitly installed.
|
||||
|
||||
The other way of using `become` does not replace but add to the top of
|
||||
the behavior stack. In this case care must be taken to ensure that the number
|
||||
the behavior stack. In this case, care must be taken to ensure that the number
|
||||
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).
|
||||
|
|
@ -1165,11 +1161,9 @@ actor's state which have the same property.
|
|||
|
||||
However, the @scala[`Stash` trait’s] @java[`AbstractActorWithStash`]
|
||||
implementation of `preRestart` will call `unstashAll()`. This means
|
||||
that prior to the actor restarting, it will transfer all stashed
|
||||
messages back to the actor's mailbox.
|
||||
that before the actor restarts, it will transfer all stashed messages back to the actor's mailbox.
|
||||
|
||||
The result of this is that when an actor is restarted, any stashed
|
||||
messages will be delivered to the new incarnation of the actor.
|
||||
The result of this is that when an actor is restarted, any stashed messages will be delivered to the new incarnation of the actor.
|
||||
This is usually the desired behavior.
|
||||
|
||||
@@@ note
|
||||
|
|
@ -1190,7 +1184,7 @@ however you should keep in mind that "first match" wins - which may be important
|
|||
|
||||
For example, imagine you have a set of actors which are either `Producers` or `Consumers`, yet sometimes it makes sense to
|
||||
have an actor share both behaviors. This can be achieved without having to duplicate code by extracting the behaviors to
|
||||
traits and implementing the actor's `receive` as combination of these partial functions.
|
||||
traits and implementing the actor's `receive` as a combination of these partial functions.
|
||||
|
||||
@@snip [ActorDocSpec.scala](/akka-docs/src/test/scala/docs/actor/ActorDocSpec.scala) { #receive-orElse }
|
||||
|
||||
|
|
@ -1204,7 +1198,7 @@ The rich lifecycle hooks of Actors provide a useful toolkit to implement various
|
|||
lifetime of an `ActorRef`, an actor can potentially go through several restarts, where the old instance is replaced by
|
||||
a fresh one, invisibly to the outside observer who only sees the `ActorRef`.
|
||||
|
||||
Initialization might be necessary every time an actor is instantiated,
|
||||
Initialization might be necessary every time an actor is instantiated,
|
||||
but sometimes one needs initialization to happen only at the birth of the first instance when the
|
||||
`ActorRef` is created. The following sections provide patterns for different initialization needs.
|
||||
|
||||
|
|
@ -1220,7 +1214,7 @@ restarts. The following section provides a pattern for this case.
|
|||
### Initialization via preStart
|
||||
|
||||
The method `preStart()` of an actor is only called once directly during the initialization of the first instance, that
|
||||
is, at creation of its `ActorRef`. In the case of restarts, `preStart()` is called from `postRestart()`, therefore
|
||||
is, at the creation of its `ActorRef`. In the case of restarts, `preStart()` is called from `postRestart()`, therefore
|
||||
if not overridden, `preStart()` is called on every restart. However, by overriding `postRestart()` one can disable
|
||||
this behavior, and ensure that there is only one call to `preStart()`.
|
||||
|
||||
|
|
@ -1243,7 +1237,7 @@ For more information see @ref:[What Restarting Means](general/supervision.md#sup
|
|||
### Initialization via message passing
|
||||
|
||||
There are cases when it is impossible to pass all the information needed for actor initialization in the constructor,
|
||||
for example in the presence of circular dependencies. In this case the actor should listen for an initialization message,
|
||||
for example in the presence of circular dependencies. In this case, the actor should listen for an initialization message,
|
||||
and use `become()` or a finite state-machine state transition to encode the initialized and uninitialized states
|
||||
of the actor.
|
||||
|
||||
|
|
|
|||
|
|
@ -14,12 +14,12 @@ It is not advised to build new applications with Cluster Client, and existing us
|
|||
To use Cluster Client, 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-cluster-tools_$scala.binary.version$
|
||||
version=AkkaVersion
|
||||
bomGroup=com.typesafe.akka bomArtifact=akka-bom_$scala.binary.version$ bomVersionSymbols=AkkaVersion
|
||||
symbol1=AkkaVersion
|
||||
value1="$akka.version$"
|
||||
group=com.typesafe.akka
|
||||
artifact=akka-cluster-tools_$scala.binary.version$
|
||||
version=AkkaVersion
|
||||
}
|
||||
|
||||
@@project-info{ projectId="akka-cluster-tools" }
|
||||
|
|
@ -32,29 +32,28 @@ another cluster. It only needs to know the location of one (or more) nodes to us
|
|||
contact points. It will establish a connection to a @apidoc[akka.cluster.client.ClusterReceptionist] somewhere in
|
||||
the cluster. It will monitor the connection to the receptionist and establish a new
|
||||
connection if the link goes down. When looking for a new receptionist it uses fresh
|
||||
contact points retrieved from previous establishment, or periodically refreshed contacts,
|
||||
contact points retrieved from the previous establishment, or periodically refreshed contacts,
|
||||
i.e. not necessarily the initial contact points.
|
||||
|
||||
Using the @apidoc[ClusterClient] for communicating with a cluster from the outside requires that the system with the client
|
||||
can both connect and be connected to with Akka Remoting from all the nodes in the cluster with a receptionist.
|
||||
This creates a tight coupling in that the client and cluster systems may need to have the same version of
|
||||
both Akka, libraries, message classes, serializers and potentially even the JVM. In many cases it is a better solution
|
||||
to use a more explicit and decoupling protocol such as [HTTP](https://doc.akka.io/docs/akka-http/current/index.html) or
|
||||
can both connect and be connected with Akka Remoting from all the nodes in the cluster with a receptionist.
|
||||
This creates a tight coupling in that the client and cluster systems may need to have the same version of both Akka, libraries, message classes, serializers and potentially even the JVM. In many cases it is a better solution
|
||||
to use a more explicit and decoupling protocol such as [HTTP](https://doc.akka.io/docs/akka-http/current/index.html) or
|
||||
[gRPC](https://doc.akka.io/docs/akka-grpc/current/).
|
||||
|
||||
Additionally since Akka Remoting is primarily designed as a protocol for Akka Cluster there is no explicit resource
|
||||
management, when a @apidoc[ClusterClient] has been used it will cause connections with the cluster until the ActorSystem is
|
||||
stopped (unlike other kinds of network clients).
|
||||
Additionally, since Akka Remoting is primarily designed as a protocol for Akka Cluster there is no explicit resource
|
||||
management, when a @apidoc[ClusterClient] has been used it will cause connections with the cluster until the ActorSystem is
|
||||
stopped (unlike other kinds of network clients).
|
||||
|
||||
@apidoc[ClusterClient] should not be used when sending messages to actors that run
|
||||
within the same cluster. Similar functionality as the @apidoc[ClusterClient] is
|
||||
provided in a more efficient way by @ref:[Distributed Publish Subscribe in Cluster](distributed-pub-sub.md) for actors that
|
||||
provided more efficiently by @ref:[Distributed Publish Subscribe in Cluster](distributed-pub-sub.md) for actors that
|
||||
belong to the same cluster.
|
||||
|
||||
It is necessary that the connecting system has its `akka.actor.provider` set to `remote` or `cluster` when using
|
||||
The connecting system must have its `akka.actor.provider` set to `remote` or `cluster` when using
|
||||
the cluster client.
|
||||
|
||||
The receptionist is supposed to be started on all nodes, or all nodes with specified role,
|
||||
The receptionist is supposed to be started on all nodes, or all nodes with a specified role,
|
||||
in the cluster. The receptionist can be started with the @apidoc[akka.cluster.client.ClusterReceptionist] extension
|
||||
or as an ordinary actor.
|
||||
|
||||
|
|
@ -65,32 +64,31 @@ should be reachable from the client. Messages are wrapped in `ClusterClient.Send
|
|||
@scala[@scaladoc[`ClusterClient.SendToAll`](akka.cluster.client.ClusterClient$)]@java[`ClusterClient.SendToAll`] or @scala[@scaladoc[`ClusterClient.Publish`](akka.cluster.client.ClusterClient$)]@java[`ClusterClient.Publish`].
|
||||
|
||||
Both the @apidoc[ClusterClient] and the @apidoc[ClusterClientReceptionist] emit events that can be subscribed to.
|
||||
The @apidoc[ClusterClient] sends out notifications in relation to having received a list of contact points
|
||||
The @apidoc[ClusterClient] sends out notifications about the list of contact points received
|
||||
from the @apidoc[ClusterClientReceptionist]. One use of this list might be for the client to record its
|
||||
contact points. A client that is restarted could then use this information to supersede any previously
|
||||
configured contact points.
|
||||
|
||||
The @apidoc[ClusterClientReceptionist] sends out notifications in relation to having received a contact
|
||||
from a @apidoc[ClusterClient]. This notification enables the server containing the receptionist to become aware of
|
||||
what clients are connected.
|
||||
what clients are connected to.
|
||||
|
||||
1. **ClusterClient.Send**
|
||||
|
||||
The message will be delivered to one recipient with a matching path, if any such
|
||||
exists. If several entries match the path the message will be delivered
|
||||
to one random destination. The sender of the message can specify that local
|
||||
affinity is preferred, i.e. the message is sent to an actor in the same local actor
|
||||
system as the used receptionist actor, if any such exists, otherwise random to any other
|
||||
matching entry.
|
||||
The message will be delivered to one recipient with a matching path if any such exists. If several entries match the path the message will be delivered
|
||||
to one random destination. The sender of the message can specify that local
|
||||
affinity is preferred, i.e. the message is sent to an actor in the same local actor
|
||||
system as the used receptionist actor, if any such exists, otherwise random to any other
|
||||
matching entry.
|
||||
|
||||
2. **ClusterClient.SendToAll**
|
||||
|
||||
The message will be delivered to all recipients with a matching path.
|
||||
The message will be delivered to all recipients with a matching path.
|
||||
|
||||
3. **ClusterClient.Publish**
|
||||
|
||||
The message will be delivered to all recipients Actors that have been registered as subscribers
|
||||
to the named topic.
|
||||
The message will be delivered to all recipients Actors that have been registered as subscribers
|
||||
to the named topic.
|
||||
|
||||
Response messages from the destination actor are tunneled via the receptionist
|
||||
to avoid inbound connections from other cluster nodes to the client:
|
||||
|
|
@ -99,7 +97,7 @@ to avoid inbound connections from other cluster nodes to the client:
|
|||
but the receptionist
|
||||
* @scala[@scaladoc[`sender()`](akka.actor.Actor)] @java[@javadoc[`getSender()`](akka.actor.Actor)] of the response messages, sent back from the destination and seen by the client,
|
||||
is `deadLetters`
|
||||
|
||||
|
||||
since the client should normally send subsequent messages via the @apidoc[ClusterClient].
|
||||
It is possible to pass the original sender inside the reply messages if
|
||||
the client is supposed to communicate directly to the actor in the cluster.
|
||||
|
|
@ -115,7 +113,7 @@ of these actors. As always, additional logic should be implemented in the destin
|
|||
|
||||
## An Example
|
||||
|
||||
On the cluster nodes first start the receptionist. Note, it is recommended to load the extension
|
||||
On the cluster nodes, first start the receptionist. Note, it is recommended to load the extension
|
||||
when the actor system is started by defining it in the `akka.extensions` configuration property:
|
||||
|
||||
```
|
||||
|
|
@ -130,7 +128,7 @@ Scala
|
|||
Java
|
||||
: @@snip [ClusterClientTest.java](/akka-cluster-tools/src/test/java/akka/cluster/client/ClusterClientTest.java) { #server }
|
||||
|
||||
On the client you create the @apidoc[ClusterClient] actor and use it as a gateway for sending
|
||||
On the client, you create the @apidoc[ClusterClient] actor and use it as a gateway for sending
|
||||
messages to the actors identified by their path (without address information) somewhere
|
||||
in the cluster.
|
||||
|
||||
|
|
@ -214,9 +212,9 @@ with different settings if needed.
|
|||
When the cluster client is started it must be provided with a list of initial contacts which are cluster
|
||||
nodes where receptionists are running. It will then repeatedly (with an interval configurable
|
||||
by `establishing-get-contacts-interval`) try to contact those until it gets in contact with one of them.
|
||||
While running, the list of contacts are continuously updated with data from the receptionists (again, with an
|
||||
While running, the list of contacts is continuously updated with data from the receptionists (again, with an
|
||||
interval configurable with `refresh-contacts-interval`), so that if there are more receptionists in the cluster
|
||||
than the initial contacts provided to the client the client will learn about them.
|
||||
than the initial contacts provided to the client will learn about them.
|
||||
|
||||
While the client is running it will detect failures in its connection to the receptionist by heartbeats
|
||||
if more than a configurable amount of heartbeats are missed the client will try to reconnect to its known
|
||||
|
|
@ -234,7 +232,7 @@ contacts can be fetched and a new cluster client started.
|
|||
## Migration to Akka gRPC
|
||||
|
||||
Cluster Client is deprecated and it is not advised to build new applications with it.
|
||||
As a replacement we recommend using [Akka gRPC](https://doc.akka.io/docs/akka-grpc/current/)
|
||||
As a replacement, we recommend using [Akka gRPC](https://doc.akka.io/docs/akka-grpc/current/)
|
||||
with an application-specific protocol. The benefits of this approach are:
|
||||
|
||||
* Improved security by using TLS for gRPC (HTTP/2) versus exposing Akka Remoting outside the Akka Cluster
|
||||
|
|
@ -262,13 +260,13 @@ It will not be provided as a published artifact.
|
|||
* [akka-samples/akka-sample-cluster-cluster-client-grpc-scala](https://github.com/akka/akka-samples/tree/2.6/akka-sample-cluster-client-grpc-scala) implemented in Scala
|
||||
* [akka-samples/akka-sample-cluster-cluster-client-grpc-java](https://github.com/akka/akka-samples/tree/2.6/akka-sample-cluster-client-grpc-java) implemented in Java
|
||||
|
||||
The example is still using an actor on the client side to have an API that is very close
|
||||
The example is still using an actor on the client-side to have an API that is very close
|
||||
to the original Cluster Client. The messages this actor can handle correspond to the
|
||||
@ref:[Distributed Pub Sub](distributed-pub-sub.md) messages on the server side, such as
|
||||
@ref:[Distributed Pub Sub](distributed-pub-sub.md) messages on the server-side, such as
|
||||
`ClusterClient.Send` and `ClusterClient.Publish`.
|
||||
|
||||
The `ClusterClient` actor delegates those messages to the gRPC client, and on the
|
||||
server side those are translated and delegated to the destination actors that
|
||||
server-side those are translated and delegated to the destination actors that
|
||||
are registered via the `ClusterClientReceptionist` in the same way as in the original.
|
||||
|
||||
Akka gRPC is used as the transport for the messages between client and server, instead of Akka Remoting.
|
||||
|
|
@ -276,7 +274,7 @@ Akka gRPC is used as the transport for the messages between client and server, i
|
|||
The application specific messages are wrapped and serialized with Akka Serialization,
|
||||
which means that care must be taken to keep wire compatibility when changing any messages used
|
||||
between the client and server. The Akka configuration of Akka serializers must be the same (or
|
||||
being compatible) on client and server.
|
||||
being compatible) on the client and the server.
|
||||
|
||||
#### Next steps
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue