Clarify supervision of singleton actors (#25681)

* Clarify supervision of singleton actors
* Document supervision for typed singletons
This commit is contained in:
Christopher Batey 2018-10-08 13:42:18 +01:00 committed by Johan Andrén
parent bc7d77a801
commit 2045a0fbf7
4 changed files with 68 additions and 15 deletions

View file

@ -4,16 +4,15 @@
package jdocs.akka.cluster.typed;
import akka.actor.typed.ActorRef;
import akka.actor.typed.ActorSystem;
import akka.actor.typed.Behavior;
import akka.actor.typed.Props;
import akka.actor.typed.*;
import akka.actor.typed.javadsl.Behaviors;
//#import
import akka.cluster.typed.ClusterSingleton;
import akka.cluster.typed.ClusterSingletonSettings;
import java.time.Duration;
//#import
public class SingletonCompileOnlyTest {
@ -49,21 +48,41 @@ public class SingletonCompileOnlyTest {
public static void example() {
ActorSystem system = ActorSystem.create(
Behaviors.empty(), "SingletonExample"
Behaviors.empty(), "SingletonExample"
);
//#singleton
ClusterSingleton singleton = ClusterSingleton.get(system);
// Start if needed and provide a proxy to a named singleton
ActorRef<CounterCommand> proxy = singleton.spawn(
counter("TheCounter", 0),
counter("TheCounter", 0),
"GlobalCounter",
Props.empty(),
ClusterSingletonSettings.create(system),
new GoodByeCounter()
);
proxy.tell(new Increment());
//#singleton
}
public static void backoff() {
ActorSystem system = ActorSystem.create(
Behaviors.empty(), "SingletonExample"
);
//#backoff
ClusterSingleton singleton = ClusterSingleton.get(system);
ActorRef<CounterCommand> proxy = singleton.spawn(
Behaviors.supervise(counter("TheCounter", 0))
.onFailure(SupervisorStrategy.restartWithBackoff(Duration.ofSeconds(1), Duration.ofSeconds(10), 0.2)),
"GlobalCounter",
Props.empty(),
ClusterSingletonSettings.create(system),
new GoodByeCounter()
);
proxy.tell(new Increment());
//#singleton
//#backoff
}
}

View file

@ -4,11 +4,9 @@
package docs.akka.cluster.typed
import akka.actor.typed.ActorRef
import akka.actor.typed.ActorSystem
import akka.actor.typed.Behavior
import akka.actor.typed.Props
import akka.actor.typed.{ ActorRef, ActorSystem, Behavior, Props, SupervisorStrategy }
import akka.actor.typed.scaladsl.Behaviors
import scala.concurrent.duration._
object SingletonCompileOnlySpec {
@ -39,7 +37,8 @@ object SingletonCompileOnlySpec {
val singletonManager = ClusterSingleton(system)
// Start if needed and provide a proxy to a named singleton
val proxy: ActorRef[CounterCommand] = singletonManager.spawn(
behavior = counter("TheCounter", 0),
behavior = Behaviors.supervise(counter("TheCounter", 0))
.onFailure[Exception](SupervisorStrategy.restart),
"GlobalCounter",
Props.empty,
ClusterSingletonSettings(system),
@ -49,4 +48,14 @@ object SingletonCompileOnlySpec {
proxy ! Increment
//#singleton
//#backoff
val proxyBackOff: ActorRef[CounterCommand] = singletonManager.spawn(
behavior = Behaviors.supervise(counter("TheCounter", 0))
.onFailure[Exception](SupervisorStrategy.restartWithBackoff(1.second, 10.seconds, 0.2)),
"GlobalCounter",
Props.empty,
ClusterSingletonSettings(system),
terminationMessage = GoodByeCounter
)
//#backoff
}

View file

@ -160,7 +160,15 @@ with different settings if needed.
## Supervision
Sometimes it is useful to add supervision for the Cluster Singleton itself. To accomplish this you need to add a parent supervisor actor which will be used to create the 'real' singleton instance. Below is an example implementation (credit to [this StackOverflow answer](https://stackoverflow.com/a/36716708/779513))
There are two actors that could potentially be supervised. For the `consumer` singleton created above these would be:
* Cluster singleton manager e.g. `/user/consumer` which runs on every node in the cluster
* The user actor e.g. `/user/consumer/singleton` which the manager starts on the oldest node
The Cluster singleton manager actor should not have its supervision strategy changed as it should always be running.
However it is sometimes useful to add supervision for the user actor.
To accomplish this add a parent supervisor actor which will be used to create the 'real' singleton instance.
Below is an example implementation (credit to [this StackOverflow answer](https://stackoverflow.com/a/36716708/779513))
Scala
: @@snip [ClusterSingletonSupervision.scala](/akka-docs/src/test/scala/docs/cluster/singleton/ClusterSingletonSupervision.scala) { #singleton-supervisor-actor }

View file

@ -57,6 +57,23 @@ Scala
Java
: @@snip [SingletonCompileOnlyTest.java](/akka-cluster-typed/src/test/java/jdocs/akka/cluster/typed/SingletonCompileOnlyTest.java) { #import #singleton }
## Supervision
The default @ref[supervision strategy](./fault-tolerance.md) when an exception is thrown is for an actor to be stopped.
The above example overrides this to `restart` to ensure it is always running. Another option would be to restart with
a backoff:
Scala
: @@snip [SingletonCompileOnlySpec.scala](/akka-cluster-typed/src/test/scala/docs/akka/cluster/typed/SingletonCompileOnlySpec.scala) { #backoff}
Java
: @@snip [SingletonCompileOnlyTest.java](/akka-cluster-typed/src/test/java/jdocs/akka/cluster/typed/SingletonCompileOnlyTest.java) { #backoff}
Be aware that this means there will be times when the singleton won't be running as restart is delayed.
See @ref[Fault Tolerance](./fault-tolerance.md) for a full list of supervision options.
## Accessing singleton of another data centre
TODO