diff --git a/akka-docs/src/main/paradox/cluster-sharding.md b/akka-docs/src/main/paradox/cluster-sharding.md index 7f1aeadc70..6065e71642 100644 --- a/akka-docs/src/main/paradox/cluster-sharding.md +++ b/akka-docs/src/main/paradox/cluster-sharding.md @@ -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 diff --git a/akka-docs/src/main/paradox/fault-tolerance.md b/akka-docs/src/main/paradox/fault-tolerance.md index f1d4245896..a80c246d20 100644 --- a/akka-docs/src/main/paradox/fault-tolerance.md +++ b/akka-docs/src/main/paradox/fault-tolerance.md @@ -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 [1] 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. + +> [1] 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` trait’s] @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. diff --git a/akka-docs/src/main/paradox/general/actor-systems.md b/akka-docs/src/main/paradox/general/actor-systems.md index 83a1533064..3bcf3117f6 100644 --- a/akka-docs/src/main/paradox/general/actor-systems.md +++ b/akka-docs/src/main/paradox/general/actor-systems.md @@ -23,84 +23,73 @@ 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. + if avoidable), this actor should source out any possibly dangerous sub-tasks + 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 actor’s 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. + watch that other actor’s liveness and act upon receiving a termination + 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. -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. +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 — and actor systems are a perfect fit to form +a distributed application. ## Actor Best Practices 1. Actors should be like nice co-workers: do their job efficiently without -bothering everyone else needlessly and avoid hogging resources. Translated -to programming this means to process events and generate responses (or more -requests) in an event-driven manner. Actors should not block (i.e. passively -wait while occupying a Thread) on some external entity—which might be a -lock, a network socket, etc.—unless it is unavoidable; in the latter case -see below. + bothering everyone else needlessly and avoid hogging resources. Translated + to programming this means to process events and generate responses (or more + requests) in an event-driven manner. Actors should not block (i.e. passively + wait while occupying a Thread) on some external entity—which might be a + lock, a network socket, etc.—unless it is unavoidable; in the latter case + see below. 2. Do not pass mutable objects between actors. In order to ensure that, prefer -immutable messages. If the encapsulation of actors is broken by exposing -their mutable state to the outside, you are back in normal Java concurrency -land with all the drawbacks. + immutable messages. If the encapsulation of actors is broken by exposing + their mutable state to the outside, you are back in normal Java concurrency + land with all the drawbacks. 3. Actors are made to be containers for behavior and state, embracing this -means to not routinely send behavior within messages (which may be tempting -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 -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. + means to not routinely send behavior within messages (which may be tempting + 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. 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. ## What you should not concern yourself with @@ -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). diff --git a/akka-docs/src/main/paradox/general/actors.md b/akka-docs/src/main/paradox/general/actors.md index f08c70de6f..28f0354ff9 100644 --- a/akka-docs/src/main/paradox/general/actors.md +++ b/akka-docs/src/main/paradox/general/actors.md @@ -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 diff --git a/akka-docs/src/main/paradox/general/addressing.md b/akka-docs/src/main/paradox/general/addressing.md index 267a98b2b2..ce7fd834a7 100644 --- a/akka-docs/src/main/paradox/general/addressing.md +++ b/akka-docs/src/main/paradox/general/addressing.md @@ -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 system’s 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. - - -### 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 actor’s 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 system’s 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 actor’s path) do not -represent the same actor. However, looking up the child’s 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. diff --git a/akka-docs/src/main/paradox/general/configuration.md b/akka-docs/src/main/paradox/general/configuration.md index 57c077be3e..a5bfa49351 100644 --- a/akka-docs/src/main/paradox/general/configuration.md +++ b/akka-docs/src/main/paradox/general/configuration.md @@ -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 @@ -203,7 +198,7 @@ This implies that putting Akka on the boot class path will yield ## Application specific settings The configuration can also be used for application specific settings. -A good practice is to place those settings in an @ref:[Extension](../extending-akka.md#extending-akka-settings). +A good practice is to place those settings in an @ref:[Extension](../extending-akka.md#extending-akka-settings). ## Configuring multiple ActorSystem @@ -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) + +### akka-actor-typed + +@@snip [reference.conf](/akka-actor-typed/src/main/resources/reference.conf) + + +### akka-cluster-typed + +@@snip [reference.conf](/akka-cluster-typed/src/main/resources/reference.conf) + ### akka-cluster @@snip [reference.conf](/akka-cluster/src/main/resources/reference.conf) + +### akka-discovery + +@@snip [reference.conf](/akka-discovery/src/main/resources/reference.conf) + + +### akka-coordination + +@@snip [reference.conf](/akka-coordination/src/main/resources/reference.conf) + ### akka-multi-node-testkit @@snip [reference.conf](/akka-multi-node-testkit/src/main/resources/reference.conf) + +### akka-persistence-typed + +@@snip [reference.conf](/akka-persistence-typed/src/main/resources/reference.conf) + ### akka-persistence @@snip [reference.conf](/akka-persistence/src/main/resources/reference.conf) - -### akka-remote + +### 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) -### akka-remote (artery) +### akka-remote artery @@snip [reference.conf](/akka-remote/src/main/resources/reference.conf) { #shared #artery type=none } + +### akka-remote classic (deprecated) + +@@snip [reference.conf](/akka-remote/src/main/resources/reference.conf) { #shared #classic type=none } + ### 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) + +### akka-cluster-sharding-typed + +@@snip [reference.conf](/akka-cluster-sharding-typed/src/main/resources/reference.conf) + ### 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) + + +### akka-stream + +@@snip [reference.conf](/akka-stream/src/main/resources/reference.conf) + + +### akka-stream-testkit + +@@snip [reference.conf](/akka-stream-testkit/src/main/resources/reference.conf) + diff --git a/akka-docs/src/main/paradox/general/jmm.md b/akka-docs/src/main/paradox/general/jmm.md index 9b91cd8483..af72696576 100644 --- a/akka-docs/src/main/paradox/general/jmm.md +++ b/akka-docs/src/main/paradox/general/jmm.md @@ -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. diff --git a/akka-docs/src/main/paradox/general/message-delivery-reliability.md b/akka-docs/src/main/paradox/general/message-delivery-reliability.md index f3e9b70ea7..6cf09fe069 100644 --- a/akka-docs/src/main/paradox/general/message-delivery-reliability.md +++ b/akka-docs/src/main/paradox/general/message-delivery-reliability.md @@ -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. diff --git a/akka-docs/src/main/paradox/general/remoting.md b/akka-docs/src/main/paradox/general/remoting.md index 30ac482a4b..f0416095bc 100644 --- a/akka-docs/src/main/paradox/general/remoting.md +++ b/akka-docs/src/main/paradox/general/remoting.md @@ -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). - ## 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. diff --git a/akka-docs/src/main/paradox/general/supervision.md b/akka-docs/src/main/paradox/general/supervision.md index 363d3de07f..e9e07b3b50 100644 --- a/akka-docs/src/main/paradox/general/supervision.md +++ b/akka-docs/src/main/paradox/general/supervision.md @@ -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) ## 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 actor’s 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. - -## 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). - - -### `/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 guardian’s 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 guardian’s 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 system’s `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. ## 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 child’s `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 instance’s `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 target’s 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. - -### 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 [1] 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. - -> [1] 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` trait’s] @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 -children’s 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). diff --git a/akka-docs/src/main/paradox/images/actor-paths-overview.png b/akka-docs/src/main/paradox/images/actor-paths-overview.png new file mode 100644 index 0000000000..1553b5fab2 Binary files /dev/null and b/akka-docs/src/main/paradox/images/actor-paths-overview.png differ diff --git a/akka-docs/src/main/paradox/index-actors.md b/akka-docs/src/main/paradox/index-actors.md index e4425384fd..f5327d4c94 100644 --- a/akka-docs/src/main/paradox/index-actors.md +++ b/akka-docs/src/main/paradox/index-actors.md @@ -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) diff --git a/akka-docs/src/main/paradox/index-classic.md b/akka-docs/src/main/paradox/index-classic.md index df16413b6a..4b3893dcd4 100644 --- a/akka-docs/src/main/paradox/index-classic.md +++ b/akka-docs/src/main/paradox/index-classic.md @@ -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) @@@ diff --git a/akka-docs/src/main/paradox/classic/index-utilities.md b/akka-docs/src/main/paradox/index-utilities-classic.md similarity index 68% rename from akka-docs/src/main/paradox/classic/index-utilities.md rename to akka-docs/src/main/paradox/index-utilities-classic.md index 682a6a55b7..f6b98d9699 100644 --- a/akka-docs/src/main/paradox/classic/index-utilities.md +++ b/akka-docs/src/main/paradox/index-utilities-classic.md @@ -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) @@@ diff --git a/akka-docs/src/main/paradox/persistence.md b/akka-docs/src/main/paradox/persistence.md index 5fd5064f94..712d6086dc 100644 --- a/akka-docs/src/main/paradox/persistence.md +++ b/akka-docs/src/main/paradox/persistence.md @@ -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 diff --git a/akka-docs/src/main/paradox/routing.md b/akka-docs/src/main/paradox/routing.md index b37662e115..1642d881af 100644 --- a/akka-docs/src/main/paradox/routing.md +++ b/akka-docs/src/main/paradox/routing.md @@ -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. diff --git a/akka-docs/src/main/paradox/stream/stream-error.md b/akka-docs/src/main/paradox/stream/stream-error.md index 47aa365343..cce687e437 100644 --- a/akka-docs/src/main/paradox/stream/stream-error.md +++ b/akka-docs/src/main/paradox/stream/stream-error.md @@ -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 diff --git a/akka-docs/src/main/paradox/supervision-classic.md b/akka-docs/src/main/paradox/supervision-classic.md new file mode 100644 index 0000000000..cb704ecd33 --- /dev/null +++ b/akka-docs/src/main/paradox/supervision-classic.md @@ -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. + + +## 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 actor’s 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. + +@@@ + + +## 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). + + +### `/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 guardian’s 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 guardian’s 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 system’s `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 +children’s 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). + + + + diff --git a/akka-docs/src/main/paradox/typed/fault-tolerance.md b/akka-docs/src/main/paradox/typed/fault-tolerance.md index 238c384180..b10c7fd586 100644 --- a/akka-docs/src/main/paradox/typed/fault-tolerance.md +++ b/akka-docs/src/main/paradox/typed/fault-tolerance.md @@ -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 } + ## 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 diff --git a/akka-docs/src/test/java/jdocs/actor/typed/SharedMutableStateDocTest.java b/akka-docs/src/test/java/jdocs/actor/typed/SharedMutableStateDocTest.java new file mode 100644 index 0000000000..86341ec8d1 --- /dev/null +++ b/akka-docs/src/test/java/jdocs/actor/typed/SharedMutableStateDocTest.java @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2009-2019 Lightbend Inc. + */ + +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 expensiveCalculation() { + throw new UnsupportedOperationException("just a sample signature"); + } + + class Query { + public final ActorRef replyTo; + + public Query(ActorRef replyTo) { + this.replyTo = replyTo; + } + } + + // #mutable-state + class MyActor extends AbstractBehavior { + + interface Command {} + + class Message implements Command { + public final ActorRef otherActor; + + public Message(ActorRef replyTo) { + this.otherActor = replyTo; + } + } + + class UpdateState implements Command { + public final String newState; + + public UpdateState(String newState) { + this.newState = newState; + } + } + + private final ActorContext context; + + private String state = ""; + private Set mySet = new HashSet<>(); + + public MyActor(ActorContext context) { + this.context = context; + } + + @Override + public Receive createReceive() { + return newReceiveBuilder() + .onMessage(Message.class, this::onMessage) + .onMessage(UpdateState.class, this::onUpdateState) + .build(); + } + + private Behavior 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 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 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 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 +} diff --git a/akka-docs/src/test/java/jdocs/config/ConfigDoc.java b/akka-docs/src/test/java/jdocs/config/ConfigDoc.java deleted file mode 100644 index 3b8702fa15..0000000000 --- a/akka-docs/src/test/java/jdocs/config/ConfigDoc.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2009-2019 Lightbend Inc. - */ - -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; - } -} diff --git a/akka-docs/src/test/java/jdocs/config/ConfigDocTest.java b/akka-docs/src/test/java/jdocs/config/ConfigDocTest.java new file mode 100644 index 0000000000..9d10574caf --- /dev/null +++ b/akka-docs/src/test/java/jdocs/config/ConfigDocTest.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2009-2019 Lightbend Inc. + */ + +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 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 system = + ActorSystem.create(rootBehavior, "MySystem", ConfigFactory.load(customConf)); + // #custom-config + + ActorTestKit.shutdown(system); + } + + public void compileOnlyPrintConfig() { + // #dump-config + ActorSystem system = ActorSystem.create(rootBehavior, "MySystem"); + system.logConfiguration(); + // #dump-config + } + + public void compileOnlySeparateApps() { + // #separate-apps + Config config = ConfigFactory.load(); + ActorSystem app1 = + ActorSystem.create(rootBehavior, "MyApp1", config.getConfig("myapp1").withFallback(config)); + ActorSystem 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; + } +} diff --git a/akka-docs/src/test/scala/docs/actor/typed/SharedMutableStateDocSpec.scala b/akka-docs/src/test/scala/docs/actor/typed/SharedMutableStateDocSpec.scala new file mode 100644 index 0000000000..7c5dd7c548 --- /dev/null +++ b/akka-docs/src/test/scala/docs/actor/typed/SharedMutableStateDocSpec.scala @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2009-2019 Lightbend Inc. + */ + +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 +} diff --git a/akka-docs/src/test/scala/docs/config/ConfigDocSpec.scala b/akka-docs/src/test/scala/docs/config/ConfigDocSpec.scala index 9a14ab3e3f..b6ca5b5234 100644 --- a/akka-docs/src/test/scala/docs/config/ConfigDocSpec.scala +++ b/akka-docs/src/test/scala/docs/config/ConfigDocSpec.scala @@ -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) } }