General concepts docs ported to typed (#27765)

This commit is contained in:
Johan Andrén 2019-09-27 09:50:34 +02:00 committed by GitHub
parent ea74f905ea
commit 0719de035b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 814 additions and 624 deletions

View file

@ -209,7 +209,7 @@ Java
Note that stopped entities will be started again when a new message is targeted to the entity.
If 'on stop' backoff supervision strategy is used, a final termination message must be set and used for passivation, see @ref:[Supervision](general/supervision.md#sharding)
If 'on stop' backoff supervision strategy is used, a final termination message must be set and used for passivation, see @ref:[Backoff supervisor and sharding](fault-tolerance.md#sharding)
## Graceful Shutdown

View file

@ -128,7 +128,7 @@ by overriding the `logFailure` method.
## Supervision of Top-Level Actors
Toplevel actors means those which are created using `system.actorOf()`, and
they are children of the @ref:[User Guardian](general/supervision.md#user-guardian). There are no
they are children of the @ref:[User Guardian](supervision-classic.md#user-guardian). There are no
special rules applied in this case, the guardian applies the configured
strategy.
@ -230,3 +230,105 @@ Scala
Java
: @@snip [FaultHandlingTest.java](/akka-docs/src/test/java/jdocs/actor/FaultHandlingTest.java) { #escalate-restart }
## Delayed restarts for classic actors
The supervision strategy to restart a classic actor only provides immediate restart. In some cases that will only trigger
the same failure right away and giving things a bit of time before restarting is required to actually resolve the failure.
The `akka.pattern.BackoffSupervisor` implements the so-called
*exponential backoff supervision strategy*, starting a child actor again when it fails, each time with a growing time delay between restarts.
This pattern is useful when the started actor fails <a id="^1" href="#1">[1]</a> because some external resource is not available,
and we need to give it some time to start-up again. One of the prime examples when this is useful is
when a @ref:[PersistentActor](persistence.md) fails (by stopping) with a persistence failure - which indicates that
the database may be down or overloaded, in such situations it makes most sense to give it a little bit of time
to recover before the persistent actor is started.
> <a id="1" href="#^1">[1]</a> A failure can be indicated in two different ways; by an actor stopping or crashing.
### Supervision strategies
There are two basic supervision strategies available for backoff:
* 'On failure': The supervisor will terminate and then start the supervised actor if it crashes. If the supervised actor stops normally (e.g. through `context.stop`), the supervisor will be terminated and no further attempt to start the supervised actor will be done.
* 'On stop': The supervisor will terminate and then start the supervised actor if it terminates in any way (consider this for `PersistentActor` since they stop on persistence failures instead of crashing)
To note that this supervision strategy does not restart the actor but rather stops and starts it. Be aware of it if you
use @scala[`Stash` traits] @java[`AbstractActorWithStash`] in combination with the backoff supervision strategy.
The `preRestart` hook will not be executed if the supervised actor fails or stops and you will miss the opportunity
to unstash the messages.
### Sharding
If the 'on stop' strategy is used for sharded actors a final termination message should be configured and used to terminate the actor on passivation. Otherwise the supervisor will just stop and start the actor again.
The termination message is configured with:
@@snip [BackoffSupervisorDocSpec.scala](/akka-docs/src/test/scala/docs/pattern/BackoffSupervisorDocSpec.scala) { #backoff-sharded }
And must be used for passivation:
@@snip [BackoffSupervisorDocSpec.scala](/akka-docs/src/test/scala/docs/pattern/BackoffSupervisorDocSpec.scala) { #backoff-sharded-passivation }
### Simple backoff
The following Scala snippet shows how to create a backoff supervisor which will start the given echo actor after it has stopped
because of a failure, in increasing intervals of 3, 6, 12, 24 and finally 30 seconds:
@@snip [BackoffSupervisorDocSpec.scala](/akka-docs/src/test/scala/docs/pattern/BackoffSupervisorDocSpec.scala) { #backoff-stop }
The above is equivalent to this Java code:
@@snip [BackoffSupervisorDocTest.java](/akka-docs/src/test/java/jdocs/pattern/BackoffSupervisorDocTest.java) { #backoff-imports }
@@snip [BackoffSupervisorDocTest.java](/akka-docs/src/test/java/jdocs/pattern/BackoffSupervisorDocTest.java) { #backoff-stop }
Using a `randomFactor` to add a little bit of additional variance to the backoff intervals
is highly recommended, in order to avoid multiple actors re-start at the exact same point in time,
for example because they were stopped due to a shared resource such as a database going down
and re-starting after the same configured interval. By adding additional randomness to the
re-start intervals the actors will start in slightly different points in time, thus avoiding
large spikes of traffic hitting the recovering shared database or other resource that they all need to contact.
The `akka.pattern.BackoffSupervisor` actor can also be configured to stop and start the actor after a delay when the actor
crashes and the supervision strategy decides that it should restart.
The following Scala snippet shows how to create a backoff supervisor which will start the given echo actor after it has crashed
because of some exception, in increasing intervals of 3, 6, 12, 24 and finally 30 seconds:
@@snip [BackoffSupervisorDocSpec.scala](/akka-docs/src/test/scala/docs/pattern/BackoffSupervisorDocSpec.scala) { #backoff-fail }
The above is equivalent to this Java code:
@@snip [BackoffSupervisorDocTest.java](/akka-docs/src/test/java/jdocs/pattern/BackoffSupervisorDocTest.java) { #backoff-imports }
@@snip [BackoffSupervisorDocTest.java](/akka-docs/src/test/java/jdocs/pattern/BackoffSupervisorDocTest.java) { #backoff-fail }
### Customization
The `akka.pattern.BackoffOnFailureOptions` and `akka.pattern.BackoffOnRestartOptions` can be used to customize the behavior of the back-off supervisor actor.
Options are:
* `withAutoReset`: The backoff is reset if no failure/stop occurs within the duration. This is the default behaviour with `minBackoff` as default value
* `withManualReset`: The child must send `BackoffSupervisor.Reset` to its backoff supervisor (parent)
* `withSupervisionStrategy`: Sets a custom `OneForOneStrategy` (as each backoff supervisor only has one child). The default strategy uses the `akka.actor.SupervisorStrategy.defaultDecider` which stops and starts the child on exceptions.
* `withMaxNrOfRetries`: Sets the maximum number of retries until the supervisor will give up (`-1` is default which means no limit of retries). Note: This is set on the supervision strategy, so setting a different strategy resets the `maxNrOfRetries`.
* `withReplyWhileStopped`: By default all messages received while the child is stopped are forwarded to dead letters. With this set, the supervisor will reply to the sender instead.
Only available on `BackoffOnStopOptions`:
* `withDefaultStoppingStrategy`: Sets a `OneForOneStrategy` with the stopping decider that stops the child on all exceptions.
* `withFinalStopMessage`: Allows to define a predicate to decide on finally stopping the child (and supervisor). Used for passivate sharded actors - see above.
Some examples:
@@snip [BackoffSupervisorDocSpec.scala](/akka-docs/src/test/scala/docs/pattern/BackoffSupervisorDocSpec.scala) { #backoff-custom-stop }
The above code sets up a back-off supervisor that requires the child actor to send a `akka.pattern.BackoffSupervisor.Reset` message
to its parent when a message is successfully processed, resetting the back-off. It also uses a default stopping strategy, any exception
will cause the child to stop.
@@snip [BackoffSupervisorDocSpec.scala](/akka-docs/src/test/scala/docs/pattern/BackoffSupervisorDocSpec.scala) { #backoff-custom-fail }
The above code sets up a back-off supervisor that stops and starts the child after back-off if MyException is thrown, any other exception will be
escalated. The back-off is automatically reset if the child does not throw any errors within 10 seconds.

View file

@ -23,59 +23,46 @@ so create one per logical application.
Like in an economic organization, actors naturally form hierarchies. One actor,
which is to oversee a certain function in the program might want to split up
its task into smaller, more manageable pieces. For this purpose, it starts child
actors which it supervises. While the details of supervision are explained
@ref:[here](supervision.md), we shall concentrate on the underlying concepts in
this section. The only prerequisite is to know that each actor has exactly one
supervisor, which is the actor that created it.
actors.
The quintessential feature of actor systems is that tasks are split up and
delegated until they become small enough to be handled in one piece. In doing
so, not only is the task itself clearly structured, but the resulting actors
can be reasoned about in terms of which messages they should process, how they
should react normally and how failure should be handled. If one actor does not
have the means for dealing with a certain situation, it sends a corresponding
failure message to its supervisor, asking for help. The recursive structure
then allows to handle failure at the right level.
should react normally and how failure should be handled.
Compare this to layered software design which easily devolves into defensive
programming with the aim of not leaking any failure out: if the problem is
communicated to the right person, a better solution can be found than if
trying to keep everything “under the carpet”.
Now, the difficulty in designing such a system is how to decide who should
supervise what. There is no single best solution, but there are a few
Now, the difficulty in designing such a system is how to decide how to
structure the work. There is no single best solution, but there are a few
guidelines which might be helpful:
* If one actor manages the work another actor is doing, e.g. by passing on
sub-tasks, then the manager should supervise the child. The reason is that
the manager knows which kind of failures are expected and how to handle
them.
* If one actor carries very important data (i.e. its state shall not be lost
if avoidable), this actor should source out any possibly dangerous sub-tasks
to children it supervises and handle failures of these children as
appropriate. Depending on the nature of the requests, it may be best to
create a new child for each request, which simplifies state management for
collecting the replies. This is known as the “Error Kernel Pattern” from
Erlang.
to children and handle failures of these children as appropriate. Depending on
the nature of the requests, it may be best to create a new child for each request,
which simplifies state management for collecting the replies. This is known as the
“Error Kernel Pattern” from Erlang.
* If one actor depends on another actor for carrying out its duty, it should
watch that other actors liveness and act upon receiving a termination
notice. This is different from supervision, as the watching party has no
influence on the supervisor strategy, and it should be noted that a
functional dependency alone is not a criterion for deciding where to place a
certain child actor in the hierarchy.
There are always exceptions to these rules, but no matter whether you
follow the rules or break them, you should always have a reason.
notice.
* If one actor has multiple responsibilities each responsibility can often be pushed
into a separate child to make the logic and state more simple.
## Configuration Container
The actor system as a collaborating ensemble of actors is the natural unit for
managing shared facilities like scheduling services, configuration, logging,
etc. Several actor systems with different configurations may co-exist within the
same JVM without problems, there is no global shared state within Akka itself.
same JVM without problems, there is no global shared state within Akka itself,
however the most common scenario will only involve a single actor system per JVM.
Couple this with the transparent communication between actor systems — within one
node or across a network connection—to see that actor systems themselves can be
used as building blocks in a functional hierarchy.
node or across a network connection — and actor systems are a perfect fit to form
a distributed application.
## Actor Best Practices
@ -96,8 +83,10 @@ using Scala closures). One of the risks is to accidentally share mutable
state between actors, and this violation of the actor model unfortunately
breaks all the properties which make programming in actors such a nice
experience.
4. Top-level actors are the innermost part of your Error Kernel, so create them
sparingly and prefer truly hierarchical systems. This has benefits with
4. The top-level actor of the actor system is the innermost part of your
Error Kernel, it should only be responsible for starting the various
sub systems of your application, and not contain much logic in itself,
prefer truly hierarchical systems. This has benefits with
respect to fault-handling (both considering the granularity of configuration
and the performance) and it also reduces the strain on the guardian actor,
which is a single point of contention if over-used.
@ -114,10 +103,9 @@ while Akka does the heavy lifting under the hood.
## Terminating ActorSystem
When you know everything is done for your application, you can call the
`terminate` method of `ActorSystem`. That will run @ref:[`CoordinatedShutdown`](../actors.md#coordinated-shutdown)
followed by stopping the guardian actor, which in turn will recursively stop all its child actors,
and finally the system guardian.
When you know everything is done for your application, you can have the user guardian
actor stop, or call the `terminate` method of `ActorSystem`. That will run @ref:[`CoordinatedShutdown`](../actors.md#coordinated-shutdown)
stopping all running actors.
If you want to execute some operations while terminating `ActorSystem`,
look at @ref:[`CoordinatedShutdown`](../actors.md#coordinated-shutdown).

View file

@ -158,12 +158,9 @@ their parent.
## Supervisor Strategy
The final piece of an actor is its strategy for handling faults of its
children. Fault handling is then done transparently by Akka, applying one
of the strategies described in @ref:[Fault Tolerance](../typed/fault-tolerance.md)
for each incoming failure.
As this strategy is fundamental to how an actor system is structured, it
cannot be changed once an actor has been created.
The final piece of an actor is its a strategy for handling unexpected exceptions - failures.
Fault handling is then done transparently by Akka, applying one of the strategies described
in @ref:[Fault Tolerance](../typed/fault-tolerance.md) for each failure.
## When an Actor Terminates

View file

@ -1,12 +1,9 @@
# Actor References, Paths and Addresses
This chapter describes how actors are identified and located within a possibly
distributed actor system. It ties into the central idea that
@ref:[Actor Systems](actor-systems.md) form intrinsic supervision hierarchies as well as that
communication between actors is transparent with respect to their placement
across multiple network nodes.
distributed Akka application.
![ActorPath.png](ActorPath.png)
![actor-paths-overview.png](../images/actor-paths-overview.png)
The above image displays the relationship between the most important entities
within an actor system, please read on for the details.
@ -15,11 +12,8 @@ within an actor system, please read on for the details.
An actor reference is a subtype of `ActorRef`, whose foremost purpose is
to support sending messages to the actor it represents. Each actor has access
to its canonical (local) reference through the `self` field; this
reference is also included as sender reference by default for all messages sent
to other actors. Conversely, during message processing the actor has access to
a reference representing the sender of the current message through the
`sender()` method.
to its canonical (local) reference through the `ActorContext.self` field; this
reference can be included in messages to other actors to get replies back.
There are several different types of actor references that are supported
depending on the configuration of the actor system:
@ -32,10 +26,6 @@ which support networking functions for those references which represent
actors within the same JVM. In order to also be reachable when sent to
other network nodes, these references include protocol and remote addressing
information.
* There is a subtype of local actor references which is used for routers (i.e.
actors mixing in the `Router` trait). Its logical structure is the
same as for the aforementioned local references, but sending a message to
them dispatches to one of their children directly instead.
* Remote actor references represent actors which are reachable using remote
communication, i.e. sending messages to them will serialize the messages
transparently and send them to the remote JVM.
@ -110,125 +100,28 @@ the creation ancestry of an actor, so it is completely deterministic as soon as
the actor systems remoting configuration (and with it the address component of
the path) is set.
### Physical Actor Paths
While the logical actor path describes the functional location within one actor
system, configuration-based remote deployment means that an actor may be
created on a different network host than its parent, i.e. within a different
actor system. In this case, following the actor path from the root guardian up
entails traversing the network, which is a costly operation. Therefore, each
actor also has a physical path, starting at the root guardian of the actor
system where the actual actor object resides. Using this path as sender
reference when querying other actors will let them reply directly to this
actor, minimizing delays incurred by routing.
One important aspect is that a physical actor path never spans multiple actor
systems or JVMs. This means that the logical path (supervision hierarchy) and
the physical path (actor deployment) of an actor may diverge if one of its
ancestors is remotely supervised.
### Actor path alias or symbolic link?
As in some real file-systems you might think of a “path alias” or “symbolic link” for an actor,
i.e. one actor may be reachable using more than one path.
However, you should note that actor hierarchy is different from file system hierarchy.
You cannot freely create actor paths like symbolic links to refer to arbitrary actors.
As described in the above logical and physical actor path sections,
an actor path must be either logical path which represents supervision hierarchy, or
physical path which represents actor deployment.
## How are Actor References obtained?
There are two general categories to how actor references may be obtained: by
creating actors or by looking them up, where the latter functionality comes in
the two flavours of creating actor references from concrete actor paths and
querying the logical actor hierarchy.
creating actors or by looking them up through the @ref:[Receptionist](../typed/actor-discovery.md#receptionist).
### Creating Actors
An actor system is typically started by creating actors beneath the guardian
actor using the `ActorSystem.actorOf` method and then using
`ActorContext.actorOf` from within the created actors to spawn the actor
An actor system is started by creating actors beneath the user guardian
actor using the `ActorContext.spawn` method and then using
`ActorContext.spawn` from within the created actors to spawn the actor
tree. These methods return a reference to the newly created actor. Each actor
has direct access (through its `ActorContext`) to references for its parent,
itself and its children. These references may be sent within messages to other actors,
enabling those to reply directly.
### Looking up Actors by Concrete Path
In addition, actor references may be looked up using the
`ActorSystem.actorSelection` method. The selection can be used for
communicating with said actor and the actor corresponding to the selection
is looked up when delivering each message.
To acquire an `ActorRef` that is bound to the life-cycle of a specific actor
you need to send a message, such as the built-in `Identify` message, to the actor
and use the `sender()` reference of a reply from the actor.
#### Absolute vs. Relative Paths
In addition to `ActorSystem.actorSelection` there is also
`ActorContext.actorSelection`, which is available inside any actor as
`context.actorSelection`. This yields an actor selection much like its twin on
`ActorSystem`, but instead of looking up the path starting from the root
of the actor tree it starts out on the current actor. Path elements consisting
of two dots (`".."`) may be used to access the parent actor. You can for
example send a message to a specific sibling:
```
context.actorSelection("../brother") ! msg
```
Absolute paths may also be looked up on *context* in the usual way, i.e.
```scala
context.actorSelection("/user/serviceA") ! msg
```
will work as expected.
### Querying the Logical Actor Hierarchy
Since the actor system forms a file-system like hierarchy, matching on paths is
possible in the same way as supported by Unix shells: you may replace (parts
of) path element names with wildcards (*«*»* and *«?»*) to formulate a
selection which may match zero or more actual actors. Because the result is not
a single actor reference, it has a different type `ActorSelection` and
does not support the full set of operations an `ActorRef` does.
Selections may be formulated using the `ActorSystem.actorSelection` and
`ActorContext.actorSelection` methods and do support sending messages:
```
context.actorSelection("../*") ! msg
```
will send *msg* to all siblings including the current actor. As for references
obtained using *actorSelection*, a traversal of the supervision hierarchy is done in
order to perform the message send. As the exact set of actors which match a
selection may change even while a message is making its way to the recipients,
it is not possible to watch a selection for liveliness changes. In order to do
that, resolve the uncertainty by sending a request and gathering all answers,
extracting the sender references, and then watch all discovered concrete
actors. This scheme of resolving a selection may be improved upon in a future
release.
<a id="actorof-vs-actorselection"></a>
### Summary: `actorOf` vs. `actorSelection`
@@@ note
What the above sections described in some detail can be summarized and
memorized as follows:
* `actorOf` only ever creates a new actor, and it creates it as a direct
child of the context on which this method is invoked (which may be any
actor or actor system).
* `actorSelection` only ever looks up existing actors when messages are
delivered, i.e. does not create actors, or verify existence of actors
when the selection is created.
@@@
## Actor Reference and Path Equality
Equality of `ActorRef` match the intention that an `ActorRef` corresponds to
@ -248,40 +141,6 @@ of the target actor is not taken into account when comparing actor paths.
When an actor is terminated, its reference will point to the dead letter mailbox,
DeathWatch will publish its final transition and in general it is not expected
to come back to life again (since the actor life cycle does not allow this).
While it is possible to create an actor at a later time with an identical
path—due to it being impossible to enforce the opposite without keeping
the set of all actors ever created available—this is not good practice:
messages sent with `actorSelection` to an actor which “died” suddenly start to work
again, but without any guarantee of ordering between this transition and any
other event, hence the new inhabitant of the path may receive messages which were destined for the
previous tenant.
It may be the right thing to do in very specific circumstances, but make sure
to confine the handling of this precisely to the actors supervisor, because
that is the only actor which can reliably detect proper deregistration of the
name, before which creation of the new child will fail.
It may also be required during testing, when the test subject depends on being
instantiated at a specific path. In that case it is best to mock its supervisor
so that it will forward the Terminated message to the appropriate point in the
test procedure, enabling the latter to await proper deregistration of the name.
## The Interplay with Remote Deployment
When an actor creates a child, the actor systems deployer will decide whether
the new actor resides in the same JVM or on another node. In the second case,
creation of the actor will be triggered via a network connection to happen in a
different JVM and consequently within a different actor system. The remote
system will place the new actor below a special path reserved for this purpose
and the supervisor of the new actor will be a remote actor reference
(representing that actor which triggered its creation). In this case,
`context.parent` (the supervisor reference) and
`context.path.parent` (the parent node in the actors path) do not
represent the same actor. However, looking up the childs name within the
supervisor will find it on the remote node, preserving logical structure e.g.
when sending to an unresolved actor reference.
![RemoteDeployment.png](RemoteDeployment.png)
## What is the Address part used for?
@ -316,11 +175,4 @@ supervisors are remote actor references
The need to structure the name space for actors like this arises from a central
and very simple design goal: everything in the hierarchy is an actor, and all
actors function in the same way. Hence you can not only look up the actors you
created, you can also look up the system guardian and send it a message (which
it will dutifully discard in this case). This powerful principle means that
there are no quirks to remember, it makes the whole system more uniform and
consistent.
If you want to read more about the top-level structure of an actor system, have
a look at @ref:[The Top-Level Supervisors](supervision.md#toplevel-supervisors).
actors function in the same way.

View file

@ -5,26 +5,15 @@ are provided. Later on you might need to amend the settings to change the defaul
or adapt for specific runtime environments. Typical examples of settings that you
might amend:
* log level and logger backend
* log level and logger backend for the Akka internals
* enable remoting
* message serializers
* definition of routers
* tuning of dispatchers
Akka uses the [Typesafe Config Library](https://github.com/typesafehub/config), which might also be a good choice
Akka uses the [Typesafe Config Library](https://github.com/lightbend/config), which might also be a good choice
for the configuration of your own application or library built with or without
Akka. This library is implemented in Java with no external dependencies; you
should have a look at its documentation (in particular about [ConfigFactory](https://lightbend.github.io/config/latest/api/com/typesafe/config/ConfigFactory.html)),
which is only summarized in the following.
@@@ warning
If you use Akka from the Scala REPL from the 2.9.x series,
and you do not provide your own ClassLoader to the ActorSystem,
start the REPL with "-Yrepl-sync" to work around a deficiency in
the REPLs provided Context ClassLoader.
@@@
Akka. This library is implemented in Java with no external dependencies;
This is only a summary of the most important parts for more details see [the config library docs](https://github.com/lightbend/config/blob/master/README.md).
## Where configuration is read from
@ -88,6 +77,9 @@ A custom `application.conf` might look like this:
akka {
# Logger config for Akka internals and classic actors, the new API relies
# directly on SLF4J and your config for the logger backend.
# Loggers to register at boot time (akka.event.Logging$DefaultLogger logs
# to STDOUT)
loggers = ["akka.event.slf4j.Slf4jLogger"]
@ -149,12 +141,13 @@ If the system or config property `akka.log-config-on-start` is set to `on`, then
complete configuration is logged at INFO level when the actor system is started. This is
useful when you are uncertain of what configuration is used.
@@@div { .group-scala }
If in doubt, you can inspect your configuration objects
before or after using them to construct an actor system:
@@@vars
```
Welcome to Scala $scala.binary_version$ (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0).
Welcome to Scala 2.12 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0).
Type in expressions to have them evaluated.
Type :help for more information.
@ -174,6 +167,7 @@ res1: java.lang.String =
}
}
```
@@@
The comments preceding every item give detailed information about the origin of
@ -181,11 +175,12 @@ the setting (file & line number) plus possible comments which were present,
e.g. in the reference configuration. The settings as merged with the reference
and parsed by the actor system can be displayed like this:
```java
final ActorSystem system = ActorSystem.create();
System.out.println(system.settings());
// this is a shortcut for system.settings().config().root().render()
```
Scala
: @@snip [ConfigDocSpec.scala](/akka-docs/src/test/scala/docs/config/ConfigDocSpec.scala) { #dump-config }
Java
: @@snip [ConfigDocTest.java](/akka-docs/src/test/java/jdocs/config/ConfigDocTest.java) { #dump-config }
## A Word About ClassLoaders
@ -229,12 +224,11 @@ my.own.setting = 42
my.other.setting = "hello"
```
```scala
val config = ConfigFactory.load()
val app1 = ActorSystem("MyApp1", config.getConfig("myapp1").withFallback(config))
val app2 = ActorSystem("MyApp2",
config.getConfig("myapp2").withOnlyPath("akka").withFallback(config))
```
Scala
: @@snip [ConfigDocSpec.scala](/akka-docs/src/test/scala/docs/config/ConfigDocSpec.scala) { #separate-apps }
Java
: @@snip [ConfigDocTest.java](/akka-docs/src/test/java/jdocs/config/ConfigDocTest.java) { #separate-apps }
These two samples demonstrate different variations of the “lift-a-subtree”
trick: in the first case, the configuration accessible from within the actor
@ -270,7 +264,13 @@ substitutions.
You may also specify and parse the configuration programmatically in other ways when instantiating
the `ActorSystem`.
@@snip [ConfigDocSpec.scala](/akka-docs/src/test/scala/docs/config/ConfigDocSpec.scala) { #imports #custom-config }
Scala
: @@snip [ConfigDocSpec.scala](/akka-docs/src/test/scala/docs/config/ConfigDocSpec.scala) { #imports #custom-config }
Java
: @@snip [ConfigDocTest.java](/akka-docs/src/test/java/jdocs/config/ConfigDocTest.java) { #imports #custom-config }
## Reading configuration from a custom location
@ -313,7 +313,12 @@ you could put a config string in code using
You can also combine your custom config with the usual config,
that might look like:
@@snip [ConfigDoc.java](/akka-docs/src/test/java/jdocs/config/ConfigDoc.java) { #java-custom-config }
Scala
: @@snip [ConfigDocSpec.scala](/akka-docs/src/test/scala/docs/config/ConfigDocSpec.scala) { #custom-config-2 }
Java
: @@snip [ConfigDocTest.java](/akka-docs/src/test/java/jdocs/config/ConfigDocTest.java) { #custom-config-2 }
When working with `Config` objects, keep in mind that there are
three "layers" in the cake:
@ -340,41 +345,6 @@ Includes at the top of `application.conf` will be overridden by
the rest of `application.conf`, while those at the bottom will
override the earlier stuff.
## Actor Deployment Configuration
Deployment settings for specific actors can be defined in the `akka.actor.deployment`
section of the configuration. In the deployment section it is possible to define
things like dispatcher, mailbox, router settings, and remote deployment.
Configuration of these features are described in the chapters detailing corresponding
topics. An example may look like this:
@@snip [ConfigDocSpec.scala](/akka-docs/src/test/scala/docs/config/ConfigDocSpec.scala) { #deployment-section }
@@@ note
The deployment section for a specific actor is identified by the
path of the actor relative to `/user`.
@@@
You can use asterisks as wildcard matches for the actor path sections, so you could specify:
`/*/sampleActor` and that would match all `sampleActor` on that level in the hierarchy.
In addition, please note:
* you can also use wildcards in the last position to match all actors at a certain level: `/someParent/*`
* you can use double-wildcards in the last position to match all child actors and their children
recursively: `/someParent/**`
* non-wildcard matches always have higher priority to match than wildcards, and single wildcard matches
have higher priority than double-wildcards, so: `/foo/bar` is considered **more specific** than
`/foo/*`, which is considered **more specific** than `/foo/**`. Only the highest priority match is used
* wildcards **cannot** be used to partially match section, like this: `/foo*/bar`, `/f*o/bar` etc.
@@@ note
Double-wildcards can only be placed in the last position.
@@@
## Listing of the Reference Configuration
Each Akka module has a reference configuration file with the default values.
@ -384,31 +354,61 @@ Each Akka module has a reference configuration file with the default values.
@@snip [reference.conf](/akka-actor/src/main/resources/reference.conf)
<a id="config-akka-actor-typed"></a>
### akka-actor-typed
@@snip [reference.conf](/akka-actor-typed/src/main/resources/reference.conf)
<a id="config-akka-cluster-typed"></a>
### akka-cluster-typed
@@snip [reference.conf](/akka-cluster-typed/src/main/resources/reference.conf)
<a id="config-akka-cluster"></a>
### akka-cluster
@@snip [reference.conf](/akka-cluster/src/main/resources/reference.conf)
<a id="config-akka-discovery"></a>
### akka-discovery
@@snip [reference.conf](/akka-discovery/src/main/resources/reference.conf)
<a id="config-akka-coordination"></a>
### akka-coordination
@@snip [reference.conf](/akka-coordination/src/main/resources/reference.conf)
<a id="config-akka-multi-node-testkit"></a>
### akka-multi-node-testkit
@@snip [reference.conf](/akka-multi-node-testkit/src/main/resources/reference.conf)
<a id="config-akka-persistence-typed"></a>
### akka-persistence-typed
@@snip [reference.conf](/akka-persistence-typed/src/main/resources/reference.conf)
<a id="config-akka-persistence"></a>
### akka-persistence
@@snip [reference.conf](/akka-persistence/src/main/resources/reference.conf)
<a id="config-akka-remote"></a>
### akka-remote
<a id="config-akka-persistence-query"></a>
### akka-persistence-query
@@snip [reference.conf](/akka-remote/src/main/resources/reference.conf) { #shared #classic type=none }
@@snip [reference.conf](/akka-persistence-query/src/main/resources/reference.conf)
<a id="config-akka-remote-artery"></a>
### akka-remote (artery)
### akka-remote artery
@@snip [reference.conf](/akka-remote/src/main/resources/reference.conf) { #shared #artery type=none }
<a id="config-akka-remote"></a>
### akka-remote classic (deprecated)
@@snip [reference.conf](/akka-remote/src/main/resources/reference.conf) { #shared #classic type=none }
<a id="config-akka-testkit"></a>
### akka-testkit
@ -424,6 +424,11 @@ Each Akka module has a reference configuration file with the default values.
@@snip [reference.conf](/akka-cluster-tools/src/main/resources/reference.conf)
<a id="config-cluster-sharding-typed"></a>
### akka-cluster-sharding-typed
@@snip [reference.conf](/akka-cluster-sharding-typed/src/main/resources/reference.conf)
<a id="config-cluster-sharding"></a>
### akka-cluster-sharding
@ -433,3 +438,14 @@ Each Akka module has a reference configuration file with the default values.
### akka-distributed-data
@@snip [reference.conf](/akka-distributed-data/src/main/resources/reference.conf)
<a id="config-akka-stream"></a>
### akka-stream
@@snip [reference.conf](/akka-stream/src/main/resources/reference.conf)
<a id="config-akka-stream-testkit"></a>
### akka-stream-testkit
@@snip [reference.conf](/akka-stream-testkit/src/main/resources/reference.conf)

View file

@ -65,8 +65,13 @@ Such are the perils of synchronized.
Since Akka runs on the JVM there are still some rules to be followed.
* Closing over internal Actor state and exposing it to other threads
Most importantly, you must not close over internal Actor state and exposing it to other threads:
Scala
: @@snip [SharedMutableStateDocSpec.scala](/akka-docs/src/test/scala/docs/actor/typed/SharedMutableStateDocSpec.scala) { #mutable-state }
Java
: @@snip [DistributedDataDocTest.java](/akka-docs/src/test/java/jdocs/actor/typed/SharedMutableStateDocTest.java) { #mutable-state }
@@snip [SharedMutableStateDocSpec.scala](/akka-docs/src/test/scala/docs/actor/SharedMutableStateDocSpec.scala) { #mutable-state }
* Messages **should** be immutable, this is to avoid the shared mutable state trap.

View file

@ -275,9 +275,12 @@ acknowledgement
* a way for the receiver to detect and discard duplicates
The third becomes necessary by virtue of the acknowledgements not being guaranteed
to arrive either. An ACK-RETRY protocol with business-level acknowledgements is
supported by @ref:[At-Least-Once Delivery](../persistence.md#at-least-once-delivery) of the Akka Persistence module. Duplicates can be
detected by tracking the identifiers of messages sent via @ref:[At-Least-Once Delivery](../persistence.md#at-least-once-delivery).
to arrive either.
An ACK-RETRY protocol with business-level acknowledgements and de-duplication using identifiers is
supported by the @ref:[At-Least-Once Delivery](../persistence.md#at-least-once-delivery) of the Classic Akka Persistence module.
Corresponding functionality for typed has not yet been implemented (see [issue #20984](https://github.com/akka/akka/issues/20984)).
Another way of implementing the third part would be to make processing the messages
idempotent on the level of the business logic.
@ -350,8 +353,8 @@ local system (if no network connection can be established) or the remote one
Every time an actor does not terminate by its own decision, there is a chance
that some messages which it sends to itself are lost. There is one which
happens quite easily in complex shutdown scenarios that is usually benign:
seeing a `akka.dispatch.Terminate` message dropped means that two
termination requests were given, but only one can succeed. In the
seeing instances of a graceful stop command for an actor being dropped means that two
stop requests were given, but only one can succeed. In the
same vein, you might see `akka.actor.Terminated` messages from children
while stopping a hierarchy of actors turning up in dead letters if the parent
is still watching the child when the parent terminates.

View file

@ -21,9 +21,7 @@ for a detailed discussion on why the second approach is bound to fail.
What is true of Akka need not be true of the application which uses it, since
designing for distributed execution poses some restrictions on what is
possible. The most obvious one is that all messages sent over the wire must be
serializable. While being a little less obvious this includes closures which
are used as actor factories (i.e. within `Props`) if the actor is to be
created on a remote node.
serializable.
Another consequence is that everything needs to be aware of all interactions
being fully asynchronous, which in a computer network might mean that it may
@ -32,19 +30,6 @@ configuration). It also means that the probability for a message to be lost is
much higher than within one JVM, where it is close to zero (still: no hard
guarantee!).
## How is Remoting Used?
We took the idea of transparency to the limit in that there is nearly no API
for the remoting layer of Akka: it is purely driven by configuration. Just
write your application according to the principles outlined in the previous
sections, then specify remote deployment of actor sub-trees in the
configuration file. This way, your application can be scaled out without having
to touch the code. The only piece of the API which allows programmatic
influence on remote deployment is that `Props` contain a field which may
be set to a specific `Deploy` instance; this has the same effect as
putting an equivalent deployment into the configuration file (if both are
given, configuration file wins).
<a id="symmetric-communication"></a>
## Peer-to-Peer vs. Client-Server
@ -74,11 +59,4 @@ In addition to being able to run different parts of an actor system on
different nodes of a cluster, it is also possible to scale up onto more cores
by multiplying actor sub-trees which support parallelization (think for example
a search engine processing different queries in parallel). The clones can then
be routed to in different fashions, e.g. round-robin. The only thing necessary
to achieve this is that the developer needs to declare a certain actor as
“withRouter”, then—in its stead—a router actor will be created which will spawn
up a configurable number of children of the desired type and route to them in
the configured fashion. Once such a router has been declared, its configuration
can be freely overridden from the configuration file, including mixing it with
the remote deployment of (some of) the children. Read more about
this in @ref:[Routing](../routing.md).
be routed to in different fashions, e.g. round-robin. See @ref:[Routing](../typed/routers.md) for more details.

View file

@ -2,121 +2,55 @@
This chapter outlines the concept behind supervision, the primitives offered
and their semantics. For details on how that translates into real code, please
refer to the corresponding chapters for Scala and Java APIs.
refer to @ref:[supervision](../typed/fault-tolerance.md).
## Sample project
You can look at the
@extref[Supervision example project](samples:akka-samples-supervision-java)
to see what this looks like in practice.
Supervision has changed since classic, for details on classic supervision see @ref:[Classic Supervision](../supervision-classic.md)
<a id="supervision-directives"></a>
## What Supervision Means
As described in @ref:[Actor Systems](actor-systems.md) supervision describes a dependency
relationship between actors: the supervisor delegates tasks to subordinates and
therefore must respond to their failures. When a subordinate detects a failure
(i.e. throws an exception), it suspends itself and all its subordinates and
sends a message to its supervisor, signaling failure. Depending on the nature
of the work to be supervised and the nature of the failure, the supervisor has
a choice of the following four options:
There are two categories of exception that can happen in an actor:
1. Resume the subordinate, keeping its accumulated internal state
2. Restart the subordinate, clearing out its accumulated internal state
3. Stop the subordinate permanently
4. Escalate the failure, thereby failing itself
1. Input validation errors, expected exceptions which can be handled with a regular try-catch
or other language and standard library tools.
1. Unexpected **failures**, for example a network resource being unavailable, a disk write failing or perhaps
a bug in the application logic.
It is important to always view an actor as part of a supervision hierarchy,
which explains the existence of the fourth choice (as a supervisor also is
subordinate to another supervisor higher up) and has implications on the first
three: resuming an actor resumes all its subordinates, restarting an actor
entails restarting all its subordinates (but see below for more details),
similarly terminating an actor will also terminate all its subordinates. It
should be noted that the default behavior of the `preRestart` hook of the
`Actor` class is to terminate all its children before restarting, but
this hook can be overridden; the recursive restart applies to all children left
after this hook has been executed.
Supervision deals with failures and should be separated from the business logic while validating data and handling
of expected exceptions is a vital part of the business logic. Therefore supervision is added to an actor as decoration
rather than something that is intermingled with the message processing logic of the actor.
Each supervisor is configured with a function translating all possible failure
causes (i.e. exceptions) into one of the four choices given above; notably,
this function does not take the failed actors identity as an input. It is
quite easy to come up with examples of structures where this might not seem
flexible enough, e.g. wishing for different strategies to be applied to
different subordinates. At this point it is vital to understand that
supervision is about forming a recursive fault handling structure. If you try
to do too much at one level, it will become hard to reason about, hence the
recommended way in this case is to add a level of supervision.
Depending on the nature of the work to be supervised and the nature of the failure, supervision
provides the following three strategies:
Akka implements a specific form called “parental supervision”. Actors can only
be created by other actors—where the top-level actor is provided by the
library—and each created actor is supervised by its parent. This restriction
makes the formation of actor supervision hierarchies implicit and encourages
sound design decisions. It should be noted that this also guarantees that
actors cannot be orphaned or attached to supervisors from the outside, which
might otherwise catch them unawares. In addition, this yields a natural and
clean shutdown procedure for (sub-trees of) actor applications.
1. Resume the actor, keeping its accumulated internal state
2. Restart the actor, clearing out its accumulated internal state, with a potential delay starting again
3. Stop the actor permanently
@@@ warning
Since actors are part of a hierarchy it can often make sense to propagate
the permanent failures upwards, if all children of an actor has stopped
unexpectedly it may make sense for the actor itself to restart or stop to
get back to a functional state. This can achieved through a combination of
supervision and watching the children to get notified when they terminate.
An example of this can be found in @ref:[Bubble failures up through the hierarchy](../typed/fault-tolerance.md#bubble).
Supervision related parent-child communication happens by special system
messages that have their own mailboxes separate from user messages. This
implies that supervision related events are not deterministically
ordered relative to ordinary messages. In general, the user cannot influence
the order of normal messages and failure notifications. For details and
example see the @ref:[Discussion: Message Ordering](message-delivery-reliability.md#message-ordering) section.
## The Top-Level actors
@@@
An actor system will during its creation start at least two actors.
<a id="toplevel-supervisors"></a>
## The Top-Level Supervisors
### `/user`: the user guardian cator
![guardians.png](guardians.png)
This is the top level user provided actor, meant to bootstrap the application
by spawning subsystems as children. When the user guardian stops the entire
actor system is shut down.
An actor system will during its creation start at least three actors, shown in
the image above. For more information about the consequences for actor paths
see @ref:[Top-Level Scopes for Actor Paths](addressing.md#toplevel-paths).
<a id="user-guardian"></a>
### `/user`: The Guardian Actor
The actor which is probably most interacted with is the parent of all
user-created actors, the guardian named `"/user"`. Actors created using
`system.actorOf()` are children of this actor. This means that when this
guardian terminates, all normal actors in the system will be shutdown, too. It
also means that this guardians supervisor strategy determines how the
top-level normal actors are supervised. Since Akka 2.1 it is possible to
configure this using the setting `akka.actor.guardian-supervisor-strategy`,
which takes the fully-qualified class-name of a
`SupervisorStrategyConfigurator`. When the guardian escalates a failure,
the root guardians response will be to terminate the guardian, which in effect
will shut down the whole actor system.
### `/system`: The System Guardian
### `/system`: the system guardian
This special guardian has been introduced in order to achieve an orderly
shut-down sequence where logging remains active while all normal actors
terminate, even though logging itself is implemented using actors. This is
realized by having the system guardian watch the user guardian and initiate its own
shut-down upon reception of the `Terminated` message. The top-level
system actors are supervised using a strategy which will restart indefinitely
upon all types of `Exception` except for
`ActorInitializationException` and `ActorKilledException`, which
will terminate the child in question. All other throwables are escalated,
which will shut down the whole actor system.
### `/`: The Root Guardian
The root guardian is the grand-parent of all so-called “top-level” actors and
supervises all the special actors mentioned in @ref:[Top-Level Scopes for Actor Paths](addressing.md#toplevel-paths) using the
`SupervisorStrategy.stoppingStrategy`, whose purpose is to terminate the
child upon any type of `Exception`. All other throwables will be
escalated … but to whom? Since every real actor has a supervisor, the
supervisor of the root guardian cannot be a real actor. And because this means
that it is “outside of the bubble”, it is called the “bubble-walker”. This is a
synthetic `ActorRef` which in effect stops its child upon the first sign
of trouble and sets the actor systems `isTerminated` status to `true` as
soon as the root guardian is fully terminated (all children recursively
stopped).
shut-down upon having seen the user guardian stop.
<a id="supervision-restart"></a>
## What Restarting Means
@ -132,8 +66,8 @@ Unless the failure is specifically recognizable, the third cause cannot be
ruled out, which leads to the conclusion that the internal state needs to be
cleared out. If the supervisor decides that its other children or itself is not
affected by the corruption—e.g. because of conscious application of the error
kernel pattern—it is therefore best to restart the child. This is carried out
by creating a new instance of the underlying `Actor` class and replacing
kernel pattern—it is therefore best to restart the actor. This is carried out
by creating a new instance of the underlying `Behavior` class and replacing
the failed instance with the fresh one inside the childs `ActorRef`;
the ability to do this is one of the reasons for encapsulating actors within
special references. The new actor then resumes processing its mailbox, meaning
@ -141,22 +75,6 @@ that the restart is not visible outside of the actor itself with the notable
exception that the message during which the failure occurred is not
re-processed.
The precise sequence of events during a restart is the following:
1. suspend the actor (which means that it will not process normal messages until
resumed), and recursively suspend all children
2. call the old instances `preRestart` hook (defaults to sending
termination requests to all children and calling `postStop`)
3. wait for all children which were requested to terminate (using
`context.stop()`) during `preRestart` to actually terminate;
this—like all actor operations—is non-blocking, the termination notice from
the last killed child will effect the progression to the next step
4. create new actor instance by invoking the originally provided factory again
5. invoke `postRestart` on the new instance (which by default also calls `preStart`)
6. send restart request to all children which were not killed in step 3;
restarted children will follow the same process recursively, from step 2
7. resume the actor
## What Lifecycle Monitoring Means
@@@ note
@ -183,145 +101,6 @@ message will be delivered irrespective of the order in which the monitoring
request and targets termination occur, i.e. you still get the message even if
at the time of registration the target is already dead.
Monitoring is particularly useful if a supervisor cannot restart its
children and has to terminate them, e.g. in case of errors during actor
initialization. In that case it should monitor those children and re-create
them or schedule itself to retry this at a later time.
Another common use case is that an actor needs to fail in the absence of an
external resource, which may also be one of its own children. If a third party
terminates a child by way of the `system.stop(child)` method or sending a
`PoisonPill`, the supervisor might well be affected.
<a id="backoff-supervisor"></a>
### Delayed restarts with the BackoffSupervisor pattern
Provided as a built-in pattern the `akka.pattern.BackoffSupervisor` implements the so-called
*exponential backoff supervision strategy*, starting a child actor again when it fails, each time with a growing time delay between restarts.
This pattern is useful when the started actor fails <a id="^1" href="#1">[1]</a> because some external resource is not available,
and we need to give it some time to start-up again. One of the prime examples when this is useful is
when a @ref:[PersistentActor](../persistence.md) fails (by stopping) with a persistence failure - which indicates that
the database may be down or overloaded, in such situations it makes most sense to give it a little bit of time
to recover before the persistent actor is started.
> <a id="1" href="#^1">[1]</a> A failure can be indicated in two different ways; by an actor stopping or crashing.
#### Supervision strategies
There are two basic supervision strategies available for backoff:
* 'On failure': The supervisor will terminate and then start the supervised actor if it crashes. If the supervised actor stops normally (e.g. through `context.stop`), the supervisor will be terminated and no further attempt to start the supervised actor will be done.
* 'On stop': The supervisor will terminate and then start the supervised actor if it terminates in any way (consider this for `PersistentActor` since they stop on persistence failures instead of crashing)
To note that this supervision strategy does not restart the actor but rather stops and starts it. Be aware of it if you
use @scala[`Stash` traits] @java[`AbstractActorWithStash`] in combination with the backoff supervision strategy.
The `preRestart` hook will not be executed if the supervised actor fails or stops and you will miss the opportunity
to unstash the messages.
#### Sharding
If the 'on stop' strategy is used for sharded actors a final termination message should be configured and used to terminate the actor on passivation. Otherwise the supervisor will just stop and start the actor again.
The termination message is configured with:
@@snip [BackoffSupervisorDocSpec.scala](/akka-docs/src/test/scala/docs/pattern/BackoffSupervisorDocSpec.scala) { #backoff-sharded }
And must be used for passivation:
@@snip [BackoffSupervisorDocSpec.scala](/akka-docs/src/test/scala/docs/pattern/BackoffSupervisorDocSpec.scala) { #backoff-sharded-passivation }
#### Simple backoff
The following Scala snippet shows how to create a backoff supervisor which will start the given echo actor after it has stopped
because of a failure, in increasing intervals of 3, 6, 12, 24 and finally 30 seconds:
@@snip [BackoffSupervisorDocSpec.scala](/akka-docs/src/test/scala/docs/pattern/BackoffSupervisorDocSpec.scala) { #backoff-stop }
The above is equivalent to this Java code:
@@snip [BackoffSupervisorDocTest.java](/akka-docs/src/test/java/jdocs/pattern/BackoffSupervisorDocTest.java) { #backoff-imports }
@@snip [BackoffSupervisorDocTest.java](/akka-docs/src/test/java/jdocs/pattern/BackoffSupervisorDocTest.java) { #backoff-stop }
Using a `randomFactor` to add a little bit of additional variance to the backoff intervals
is highly recommended, in order to avoid multiple actors re-start at the exact same point in time,
for example because they were stopped due to a shared resource such as a database going down
and re-starting after the same configured interval. By adding additional randomness to the
re-start intervals the actors will start in slightly different points in time, thus avoiding
large spikes of traffic hitting the recovering shared database or other resource that they all need to contact.
The `akka.pattern.BackoffSupervisor` actor can also be configured to stop and start the actor after a delay when the actor
crashes and the supervision strategy decides that it should restart.
The following Scala snippet shows how to create a backoff supervisor which will start the given echo actor after it has crashed
because of some exception, in increasing intervals of 3, 6, 12, 24 and finally 30 seconds:
@@snip [BackoffSupervisorDocSpec.scala](/akka-docs/src/test/scala/docs/pattern/BackoffSupervisorDocSpec.scala) { #backoff-fail }
The above is equivalent to this Java code:
@@snip [BackoffSupervisorDocTest.java](/akka-docs/src/test/java/jdocs/pattern/BackoffSupervisorDocTest.java) { #backoff-imports }
@@snip [BackoffSupervisorDocTest.java](/akka-docs/src/test/java/jdocs/pattern/BackoffSupervisorDocTest.java) { #backoff-fail }
#### Customization
The `akka.pattern.BackoffOnFailureOptions` and `akka.pattern.BackoffOnRestartOptions` can be used to customize the behavior of the back-off supervisor actor.
Options are:
* `withAutoReset`: The backoff is reset if no failure/stop occurs within the duration. This is the default behaviour with `minBackoff` as default value
* `withManualReset`: The child must send `BackoffSupervisor.Reset` to its backoff supervisor (parent)
* `withSupervisionStrategy`: Sets a custom `OneForOneStrategy` (as each backoff supervisor only has one child). The default strategy uses the `akka.actor.SupervisorStrategy.defaultDecider` which stops and starts the child on exceptions.
* `withMaxNrOfRetries`: Sets the maximum number of retries until the supervisor will give up (`-1` is default which means no limit of retries). Note: This is set on the supervision strategy, so setting a different strategy resets the `maxNrOfRetries`.
* `withReplyWhileStopped`: By default all messages received while the child is stopped are forwarded to dead letters. With this set, the supervisor will reply to the sender instead.
Only available on `BackoffOnStopOptions`:
* `withDefaultStoppingStrategy`: Sets a `OneForOneStrategy` with the stopping decider that stops the child on all exceptions.
* `withFinalStopMessage`: Allows to define a predicate to decide on finally stopping the child (and supervisor). Used for passivate sharded actors - see above.
Some examples:
@@snip [BackoffSupervisorDocSpec.scala](/akka-docs/src/test/scala/docs/pattern/BackoffSupervisorDocSpec.scala) { #backoff-custom-stop }
The above code sets up a back-off supervisor that requires the child actor to send a `akka.pattern.BackoffSupervisor.Reset` message
to its parent when a message is successfully processed, resetting the back-off. It also uses a default stopping strategy, any exception
will cause the child to stop.
@@snip [BackoffSupervisorDocSpec.scala](/akka-docs/src/test/scala/docs/pattern/BackoffSupervisorDocSpec.scala) { #backoff-custom-fail }
The above code sets up a back-off supervisor that stops and starts the child after back-off if MyException is thrown, any other exception will be
escalated. The back-off is automatically reset if the child does not throw any errors within 10 seconds.
## One-For-One Strategy vs. All-For-One Strategy
There are two classes of supervision strategies which come with Akka:
`OneForOneStrategy` and `AllForOneStrategy`. Both are configured
with a mapping from exception type to supervision directive (see
[above](#supervision-directives)) and limits on how often a child is allowed to fail
before terminating it. The difference between them is that the former applies
the obtained directive only to the failed child, whereas the latter applies it
to all siblings as well. Normally, you should use the
`OneForOneStrategy`, which also is the default if none is specified
explicitly.
The `AllForOneStrategy` is applicable in cases where the ensemble of
children has such tight dependencies among them, that a failure of one child
affects the function of the others, i.e. they are inextricably linked. Since a
restart does not clear out the mailbox, it often is best to terminate the children
upon failure and re-create them explicitly from the supervisor (by watching the
childrens lifecycle); otherwise you have to make sure that it is no problem
for any of the actors to receive a message which was queued before the restart
but processed afterwards.
Normally stopping a child (i.e. not in response to a failure) will not
automatically terminate the other children in an all-for-one strategy; this can
be done by watching their lifecycle: if the `Terminated` message
is not handled by the supervisor, it will throw a `DeathPactException`
which (depending on its supervisor) will restart it, and the default
`preRestart` action will terminate all children. Of course this can be
handled explicitly as well.
Please note that creating one-off actors from an all-for-one supervisor entails
that failures escalated by the temporary actor will affect all the permanent
ones. If this is not desired, install an intermediate supervisor; this can very
be done by declaring a router of size 1 for the worker, see
@ref:[Routing](../routing.md).

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

View file

@ -17,6 +17,7 @@ To use Classic Akka Actors, you must add the following dependency in your projec
@@@ index
* [actors](actors.md)
* [supervision overview](supervision-classic.md)
* [fault-tolerance](fault-tolerance.md)
* [dispatchers](dispatchers.md)
* [mailboxes](mailboxes.md)

View file

@ -9,6 +9,6 @@
* [index-actors](index-actors.md)
* [index-cluster](index-cluster.md)
* [index-network](index-network.md)
* [index-utilities](classic/index-utilities.md)
* [index-utilities](index-utilities-classic.md)
@@@

View file

@ -14,9 +14,9 @@ To use Utilities, you must add the following dependency in your project:
@@@ index
* [event-bus](../event-bus.md)
* [logging](../logging.md)
* [scheduler](../scheduler.md)
* [extending-akka](../extending-akka.md)
* [event-bus](event-bus.md)
* [logging](logging.md)
* [scheduler](scheduler.md)
* [extending-akka](extending-akka.md)
@@@

View file

@ -421,7 +421,7 @@ Scala
Java
: @@snip [LambdaPersistenceDocTest.java](/akka-docs/src/test/java/jdocs/persistence/LambdaPersistenceDocTest.java) { #backoff }
See @ref:[Supervision strategies](general/supervision.md#supervision-strategies) for more details about actor supervision.
See @ref:[Backoff Supervision strategies](fault-tolerance.md#supervision-strategies) for more details about actor supervision.
If persistence of an event is rejected before it is stored, e.g. due to serialization error,
`onPersistRejected` will be invoked (logging a warning by default), and the actor continues with

View file

@ -198,7 +198,7 @@ a resizer.
Sometimes, rather than having the router actor create its routees, it is desirable to create routees
separately and provide them to the router for its use. You can do this by passing in
paths of the routees to the router's configuration. Messages will be sent with `ActorSelection`
to these paths, wildcards can be and will result in the same @ref:[semantics as explicitly using `ActorSelection`](general/addressing.md#querying-the-logical-actor-hierarchy).
to these paths, wildcards can be and will result in the same semantics as explicitly using `ActorSelection`.
The example below shows how to create a router by providing it with the path strings of three
routee actors.

View file

@ -99,8 +99,7 @@ Java
## Delayed restarts with a backoff operator
Just as Akka provides the @ref:[backoff supervision pattern for actors](../general/supervision.md#backoff-supervisor), Akka streams
also provides a `RestartSource`, `RestartSink` and `RestartFlow` for implementing the so-called *exponential backoff
Akka streams provides a `RestartSource`, `RestartSink` and `RestartFlow` for implementing the so-called *exponential backoff
supervision strategy*, starting an operator again when it fails or completes, each time with a growing time delay between restarts.
This pattern is useful when the operator fails or completes because some external resource is not available

View file

@ -0,0 +1,157 @@
# Classic Supervision
This chapter outlines the concept behind the supervision in Akka Classic, for the
corresponding overview of the new APIs see @ref:[supervision](general/supervision.md)
## Sample project
You can look at the
@extref[Supervision example project](samples:akka-samples-supervision-java)
to see what this looks like in practice.
<a id="supervision-directives"></a>
## What Supervision Means
Supervision describes a dependency relationship between actors: the supervisor delegates tasks to subordinates and
therefore must respond to their failures. When a subordinate detects a failure
(i.e. throws an exception), it suspends itself and all its subordinates and
sends a message to its supervisor, signaling failure. Depending on the nature
of the work to be supervised and the nature of the failure, the supervisor has
a choice of the following four options:
1. Resume the subordinate, keeping its accumulated internal state
2. Restart the subordinate, clearing out its accumulated internal state
3. Stop the subordinate permanently
4. Escalate the failure, thereby failing itself
It is important to always view an actor as part of a supervision hierarchy,
which explains the existence of the fourth choice (as a supervisor also is
subordinate to another supervisor higher up) and has implications on the first
three: resuming an actor resumes all its subordinates, restarting an actor
entails restarting all its subordinates (but see below for more details),
similarly terminating an actor will also terminate all its subordinates. It
should be noted that the default behavior of the `preRestart` hook of the
`Actor` class is to terminate all its children before restarting, but
this hook can be overridden; the recursive restart applies to all children left
after this hook has been executed.
Each supervisor is configured with a function translating all possible failure
causes (i.e. exceptions) into one of the four choices given above; notably,
this function does not take the failed actors identity as an input. It is
quite easy to come up with examples of structures where this might not seem
flexible enough, e.g. wishing for different strategies to be applied to
different subordinates. At this point it is vital to understand that
supervision is about forming a recursive fault handling structure. If you try
to do too much at one level, it will become hard to reason about, hence the
recommended way in this case is to add a level of supervision.
Akka implements a specific form called “parental supervision”. Actors can only
be created by other actors—where the top-level actor is provided by the
library—and each created actor is supervised by its parent. This restriction
makes the formation of actor supervision hierarchies implicit and encourages
sound design decisions. It should be noted that this also guarantees that
actors cannot be orphaned or attached to supervisors from the outside, which
might otherwise catch them unawares. In addition, this yields a natural and
clean shutdown procedure for (sub-trees of) actor applications.
@@@ warning
Supervision related parent-child communication happens by special system
messages that have their own mailboxes separate from user messages. This
implies that supervision related events are not deterministically
ordered relative to ordinary messages. In general, the user cannot influence
the order of normal messages and failure notifications. For details and
example see the @ref:[Discussion: Message Ordering](general/message-delivery-reliability.md#message-ordering) section.
@@@
<a id="toplevel-supervisors"></a>
## The Top-Level Supervisors
![guardians.png](general/guardians.png)
An actor system will during its creation start at least three actors, shown in
the image above. For more information about the consequences for actor paths
see @ref:[Top-Level Scopes for Actor Paths](general/addressing.md#toplevel-paths).
<a id="user-guardian"></a>
### `/user`: The Guardian Actor
The actor which is probably most interacted with is the parent of all
user-created actors, the guardian named `"/user"`. Actors created using
`system.actorOf()` are children of this actor. This means that when this
guardian terminates, all normal actors in the system will be shutdown, too. It
also means that this guardians supervisor strategy determines how the
top-level normal actors are supervised. Since Akka 2.1 it is possible to
configure this using the setting `akka.actor.guardian-supervisor-strategy`,
which takes the fully-qualified class-name of a
`SupervisorStrategyConfigurator`. When the guardian escalates a failure,
the root guardians response will be to terminate the guardian, which in effect
will shut down the whole actor system.
### `/system`: The System Guardian
This special guardian has been introduced in order to achieve an orderly
shut-down sequence where logging remains active while all normal actors
terminate, even though logging itself is implemented using actors. This is
realized by having the system guardian watch the user guardian and initiate its own
shut-down upon reception of the `Terminated` message. The top-level
system actors are supervised using a strategy which will restart indefinitely
upon all types of `Exception` except for
`ActorInitializationException` and `ActorKilledException`, which
will terminate the child in question. All other throwables are escalated,
which will shut down the whole actor system.
### `/`: The Root Guardian
The root guardian is the grand-parent of all so-called “top-level” actors and
supervises all the special actors mentioned in @ref:[Top-Level Scopes for Actor Paths](general/addressing.md#toplevel-paths) using the
`SupervisorStrategy.stoppingStrategy`, whose purpose is to terminate the
child upon any type of `Exception`. All other throwables will be
escalated … but to whom? Since every real actor has a supervisor, the
supervisor of the root guardian cannot be a real actor. And because this means
that it is “outside of the bubble”, it is called the “bubble-walker”. This is a
synthetic `ActorRef` which in effect stops its child upon the first sign
of trouble and sets the actor systems `isTerminated` status to `true` as
soon as the root guardian is fully terminated (all children recursively
stopped).
## One-For-One Strategy vs. All-For-One Strategy
There are two classes of supervision strategies which come with Akka:
`OneForOneStrategy` and `AllForOneStrategy`. Both are configured
with a mapping from exception type to supervision directive (see
[above](#supervision-directives)) and limits on how often a child is allowed to fail
before terminating it. The difference between them is that the former applies
the obtained directive only to the failed child, whereas the latter applies it
to all siblings as well. Normally, you should use the
`OneForOneStrategy`, which also is the default if none is specified
explicitly.
The `AllForOneStrategy` is applicable in cases where the ensemble of
children has such tight dependencies among them, that a failure of one child
affects the function of the others, i.e. they are inextricably linked. Since a
restart does not clear out the mailbox, it often is best to terminate the children
upon failure and re-create them explicitly from the supervisor (by watching the
childrens lifecycle); otherwise you have to make sure that it is no problem
for any of the actors to receive a message which was queued before the restart
but processed afterwards.
Normally stopping a child (i.e. not in response to a failure) will not
automatically terminate the other children in an all-for-one strategy; this can
be done by watching their lifecycle: if the `Terminated` message
is not handled by the supervisor, it will throw a `DeathPactException`
which (depending on its supervisor) will restart it, and the default
`preRestart` action will terminate all children. Of course this can be
handled explicitly as well.
Please note that creating one-off actors from an all-for-one supervisor entails
that failures escalated by the temporary actor will affect all the permanent
ones. If this is not desired, install an intermediate supervisor; this can very
be done by declaring a router of size 1 for the worker, see
@ref:[Routing](routing.md).

View file

@ -32,7 +32,12 @@ with a fresh state that we know is valid.
## Supervision
In Akka this "somewhere else" is called supervision. Supervision allows you to declaratively describe what should happen when a certain type of exceptions are thrown inside an actor. To use supervision the actual Actor behavior is wrapped using `Behaviors.supervise`, for example to restart on `IllegalStateExceptions`:
In Akka this "somewhere else" is called supervision. Supervision allows you to declaratively describe what should happen when a certain type of exceptions are thrown inside an actor.
To use supervision the actual Actor behavior is wrapped using `Behaviors.supervise`. Typically you would wrap the actor
with supervision in the parent when spawning it as a child.
This example restarts the actor when it fails with an `IllegalStateException`:
Scala
@ -140,6 +145,7 @@ Scala
Java
: @@snip [SupervisionCompileOnlyTest.java](/akka-actor-typed-tests/src/test/java/jdocs/akka/typed/supervision/SupervisionCompileOnlyTest.java) { #restart-PreRestart-signal }
<a id="bubble"/>
## Bubble failures up through the hierarchy
In some scenarios it may be useful to push the decision about what to do on a failure upwards in the Actor hierarchy

View file

@ -0,0 +1,141 @@
/*
* Copyright (C) 2009-2019 Lightbend Inc. <https://www.lightbend.com>
*/
package jdocs.actor.typed;
import akka.actor.typed.ActorRef;
import akka.actor.typed.Behavior;
import akka.actor.typed.javadsl.AbstractBehavior;
import akka.actor.typed.javadsl.ActorContext;
import akka.actor.typed.javadsl.Receive;
import akka.actor.typed.javadsl.AskPattern;
import java.time.Duration;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
interface SharedMutableStateDocTest {
static CompletableFuture<String> expensiveCalculation() {
throw new UnsupportedOperationException("just a sample signature");
}
class Query {
public final ActorRef<String> replyTo;
public Query(ActorRef<String> replyTo) {
this.replyTo = replyTo;
}
}
// #mutable-state
class MyActor extends AbstractBehavior<MyActor.Command> {
interface Command {}
class Message implements Command {
public final ActorRef<Object> otherActor;
public Message(ActorRef<Object> replyTo) {
this.otherActor = replyTo;
}
}
class UpdateState implements Command {
public final String newState;
public UpdateState(String newState) {
this.newState = newState;
}
}
private final ActorContext<Command> context;
private String state = "";
private Set<String> mySet = new HashSet<>();
public MyActor(ActorContext<Command> context) {
this.context = context;
}
@Override
public Receive<Command> createReceive() {
return newReceiveBuilder()
.onMessage(Message.class, this::onMessage)
.onMessage(UpdateState.class, this::onUpdateState)
.build();
}
private Behavior<Command> onMessage(Message message) {
// Very bad: shared mutable object allows
// the other actor to mutate your own state,
// or worse, you might get weird race conditions
message.otherActor.tell(mySet);
// Example of incorrect approach
// Very bad: shared mutable state will cause your
// application to break in weird ways
CompletableFuture.runAsync(
() -> {
state = "This will race";
});
// Example of incorrect approach
// Very bad: shared mutable state will cause your
// application to break in weird ways
expensiveCalculation()
.whenComplete(
(result, failure) -> {
if (result != null) state = "new state: " + result;
});
// Example of correct approach
// Turn the future result into a message that is sent to
// self when future completes
CompletableFuture<String> futureResult = expensiveCalculation();
context.pipeToSelf(
futureResult,
(result, failure) -> {
if (result != null) return new UpdateState(result);
else throw new RuntimeException(failure);
});
// Another example of incorrect approach
// mutating actor state from ask future callback
CompletionStage<String> response =
AskPattern.ask(
message.otherActor,
Query::new,
Duration.ofSeconds(3),
context.getSystem().scheduler());
response.whenComplete(
(result, failure) -> {
if (result != null) state = "new state: " + result;
});
// use context.ask instead, turns the completion
// into a message sent to self
context.ask(
String.class,
message.otherActor,
Duration.ofSeconds(3),
Query::new,
(result, failure) -> {
if (result != null) return new UpdateState(result);
else throw new RuntimeException(failure);
});
return this;
}
private Behavior<Command> onUpdateState(UpdateState command) {
// safe as long as `newState` is immutable, if it is mutable we'd need to
// make a defensive copy
this.state = command.newState;
return this;
}
}
// #mutable-state
}

View file

@ -1,28 +0,0 @@
/*
* Copyright (C) 2009-2019 Lightbend Inc. <https://www.lightbend.com>
*/
package jdocs.config;
import akka.actor.ActorSystem;
import com.typesafe.config.*;
public class ConfigDoc {
public ActorSystem createConfiguredSystem() {
// #java-custom-config
// make a Config with just your special setting
Config myConfig = ConfigFactory.parseString("something=somethingElse");
// load the normal config stack (system props,
// then application.conf, then reference.conf)
Config regularConfig = ConfigFactory.load();
// override regular stack with myConfig
Config combined = myConfig.withFallback(regularConfig);
// put the result in between the overrides
// (system props) and defaults again
Config complete = ConfigFactory.load(combined);
// create ActorSystem
ActorSystem system = ActorSystem.create("myname", complete);
// #java-custom-config
return system;
}
}

View file

@ -0,0 +1,70 @@
/*
* Copyright (C) 2009-2019 Lightbend Inc. <https://www.lightbend.com>
*/
package jdocs.config;
// #imports
import akka.actor.typed.ActorSystem;
import akka.actor.typed.Behavior;
import akka.actor.typed.javadsl.Behaviors;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
// #imports
import akka.actor.testkit.typed.javadsl.ActorTestKit;
public class ConfigDocTest {
private Behavior<Void> rootBehavior = Behaviors.empty();
public void customConfig() {
// #custom-config
Config customConf = ConfigFactory.parseString("akka.log-config-on-start = on");
// ConfigFactory.load sandwiches customConfig between default reference
// config and default overrides, and then resolves it.
ActorSystem<Void> system =
ActorSystem.create(rootBehavior, "MySystem", ConfigFactory.load(customConf));
// #custom-config
ActorTestKit.shutdown(system);
}
public void compileOnlyPrintConfig() {
// #dump-config
ActorSystem<Void> system = ActorSystem.create(rootBehavior, "MySystem");
system.logConfiguration();
// #dump-config
}
public void compileOnlySeparateApps() {
// #separate-apps
Config config = ConfigFactory.load();
ActorSystem<Void> app1 =
ActorSystem.create(rootBehavior, "MyApp1", config.getConfig("myapp1").withFallback(config));
ActorSystem<Void> app2 =
ActorSystem.create(
rootBehavior,
"MyApp2",
config.getConfig("myapp2").withOnlyPath("akka").withFallback(config));
// #separate-apps
}
public ActorSystem createConfiguredSystem() {
// #custom-config-2
// make a Config with just your special setting
Config myConfig = ConfigFactory.parseString("something=somethingElse");
// load the normal config stack (system props,
// then application.conf, then reference.conf)
Config regularConfig = ConfigFactory.load();
// override regular stack with myConfig
Config combined = myConfig.withFallback(regularConfig);
// put the result in between the overrides
// (system props) and defaults again
Config complete = ConfigFactory.load(combined);
// create ActorSystem
ActorSystem system = ActorSystem.create(rootBehavior, "myname", complete);
// #custom-config-2
return system;
}
}

View file

@ -0,0 +1,94 @@
/*
* Copyright (C) 2009-2019 Lightbend Inc. <https://www.lightbend.com>
*/
package docs.actor.typed
import akka.actor.typed.scaladsl._
import akka.actor.typed.{ ActorRef, Behavior }
import akka.util.Timeout
import scala.collection.mutable
import scala.concurrent.Future
import scala.concurrent.duration._
import scala.util.{ Failure, Success }
class SharedMutableStateDocSpec {
def expensiveCalculation(): Future[String] = ???
object MyActor {
trait Command
case class Message(msg: String, replyTo: ActorRef[Any]) extends Command
case class UpdateState(newState: String) extends Command
case class Query(replyTo: ActorRef[String])
def apply(): Behavior[Command] = Behaviors.setup { context =>
new MyActor(context)
}
}
//#mutable-state
class MyActor(context: ActorContext[MyActor.Command]) extends AbstractBehavior[MyActor.Command] {
import MyActor._
var state = ""
val mySet = mutable.Set[String]()
def onMessage(cmd: MyActor.Command) = cmd match {
case Message(text, otherActor) =>
// Very bad: shared mutable object allows
// the other actor to mutate your own state,
// or worse, you might get weird race conditions
otherActor ! mySet
implicit val ec = context.executionContext
// Example of incorrect approach
// Very bad: shared mutable state will cause your
// application to break in weird ways
Future { state = "This will race" }
// Example of incorrect approach
// Very bad: shared mutable state will cause your
// application to break in weird ways
expensiveCalculation().foreach { result =>
state = s"new state: $result"
}
// Example of correct approach
// Turn the future result into a message that is sent to
// self when future completes
val futureResult = expensiveCalculation()
context.pipeToSelf(futureResult) {
case Success(result) => UpdateState(result)
case Failure(ex) => throw ex
}
// Another example of incorrect approach
// mutating actor state from ask future callback
import akka.actor.typed.scaladsl.AskPattern._
implicit val timeout = Timeout(5.seconds) // needed for `ask` below
implicit val scheduler = context.system.scheduler
val future: Future[String] = otherActor.ask(Query)
future.foreach { result =>
state = result
}
// use context.ask instead, turns the completion
// into a message sent to self
context.ask(otherActor, Query) {
case Success(result) => UpdateState(result)
case Failure(ex) => throw ex
}
this
case UpdateState(newState) =>
// safe as long as `newState` is immutable, if it is mutable we'd need to
// make a defensive copy
state = newState
this
}
}
//#mutable-state
}

View file

@ -4,33 +4,63 @@
package docs.config
import akka.actor.testkit.typed.scaladsl.ActorTestKit
import akka.actor.typed.scaladsl.Behaviors
import org.scalatest.WordSpec
import org.scalatest.Matchers
import akka.testkit.TestKit
//#imports
import akka.actor.ActorSystem
import akka.actor.typed.ActorSystem
import com.typesafe.config.ConfigFactory
//#imports
class ConfigDocSpec extends WordSpec with Matchers {
val rootBehavior = Behaviors.empty[String]
"programmatically configure ActorSystem" in {
//#custom-config
val customConf = ConfigFactory.parseString("""
akka.actor.deployment {
/my-service {
router = round-robin-pool
nr-of-instances = 3
}
}
akka.log-config-on-start = on
""")
// ConfigFactory.load sandwiches customConfig between default reference
// config and default overrides, and then resolves it.
val system = ActorSystem("MySystem", ConfigFactory.load(customConf))
val system = ActorSystem(rootBehavior, "MySystem", ConfigFactory.load(customConf))
//#custom-config
TestKit.shutdownActorSystem(system)
ActorTestKit.shutdown(system)
}
def compileOnlyPrintConfig(): Unit = {
// #dump-config
val system = ActorSystem(rootBehavior, "MySystem")
system.logConfiguration()
// #dump-config
}
def compileOnlySeparateApps(): Unit = {
// #separate-apps
val config = ConfigFactory.load()
val app1 = ActorSystem(rootBehavior, "MyApp1", config.getConfig("myapp1").withFallback(config))
val app2 = ActorSystem(rootBehavior, "MyApp2", config.getConfig("myapp2").withOnlyPath("akka").withFallback(config))
// #separate-apps
}
def moreCustomConfig(): Unit = {
// #custom-config-2
// make a Config with just your special setting
val myConfig = ConfigFactory.parseString("something=somethingElse");
// load the normal config stack (system props,
// then application.conf, then reference.conf)
val regularConfig = ConfigFactory.load();
// override regular stack with myConfig
val combined = myConfig.withFallback(regularConfig);
// put the result in between the overrides
// (system props) and defaults again
val complete = ConfigFactory.load(combined);
// create ActorSystem
val system = ActorSystem(rootBehavior, "myname", complete);
// #custom-config-2
}
"deployment section" in {
@ -76,7 +106,7 @@ class ConfigDocSpec extends WordSpec with Matchers {
}
#//#deployment-section
""")
val system = ActorSystem("MySystem", conf)
TestKit.shutdownActorSystem(system)
val system = ActorSystem(rootBehavior, "MySystem", conf)
ActorTestKit.shutdown(system)
}
}