Clarify supervision of singleton actors (#25681)
* Clarify supervision of singleton actors * Document supervision for typed singletons
This commit is contained in:
parent
bc7d77a801
commit
2045a0fbf7
4 changed files with 68 additions and 15 deletions
|
|
@ -4,16 +4,15 @@
|
||||||
|
|
||||||
package jdocs.akka.cluster.typed;
|
package jdocs.akka.cluster.typed;
|
||||||
|
|
||||||
import akka.actor.typed.ActorRef;
|
import akka.actor.typed.*;
|
||||||
import akka.actor.typed.ActorSystem;
|
|
||||||
import akka.actor.typed.Behavior;
|
|
||||||
import akka.actor.typed.Props;
|
|
||||||
import akka.actor.typed.javadsl.Behaviors;
|
import akka.actor.typed.javadsl.Behaviors;
|
||||||
|
|
||||||
//#import
|
//#import
|
||||||
import akka.cluster.typed.ClusterSingleton;
|
import akka.cluster.typed.ClusterSingleton;
|
||||||
import akka.cluster.typed.ClusterSingletonSettings;
|
import akka.cluster.typed.ClusterSingletonSettings;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
|
||||||
//#import
|
//#import
|
||||||
|
|
||||||
public class SingletonCompileOnlyTest {
|
public class SingletonCompileOnlyTest {
|
||||||
|
|
@ -49,21 +48,41 @@ public class SingletonCompileOnlyTest {
|
||||||
public static void example() {
|
public static void example() {
|
||||||
|
|
||||||
ActorSystem system = ActorSystem.create(
|
ActorSystem system = ActorSystem.create(
|
||||||
Behaviors.empty(), "SingletonExample"
|
Behaviors.empty(), "SingletonExample"
|
||||||
);
|
);
|
||||||
|
|
||||||
//#singleton
|
//#singleton
|
||||||
ClusterSingleton singleton = ClusterSingleton.get(system);
|
ClusterSingleton singleton = ClusterSingleton.get(system);
|
||||||
// Start if needed and provide a proxy to a named singleton
|
// Start if needed and provide a proxy to a named singleton
|
||||||
ActorRef<CounterCommand> proxy = singleton.spawn(
|
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",
|
"GlobalCounter",
|
||||||
Props.empty(),
|
Props.empty(),
|
||||||
ClusterSingletonSettings.create(system),
|
ClusterSingletonSettings.create(system),
|
||||||
new GoodByeCounter()
|
new GoodByeCounter()
|
||||||
);
|
);
|
||||||
|
//#backoff
|
||||||
proxy.tell(new Increment());
|
|
||||||
//#singleton
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,9 @@
|
||||||
|
|
||||||
package docs.akka.cluster.typed
|
package docs.akka.cluster.typed
|
||||||
|
|
||||||
import akka.actor.typed.ActorRef
|
import akka.actor.typed.{ ActorRef, ActorSystem, Behavior, Props, SupervisorStrategy }
|
||||||
import akka.actor.typed.ActorSystem
|
|
||||||
import akka.actor.typed.Behavior
|
|
||||||
import akka.actor.typed.Props
|
|
||||||
import akka.actor.typed.scaladsl.Behaviors
|
import akka.actor.typed.scaladsl.Behaviors
|
||||||
|
import scala.concurrent.duration._
|
||||||
|
|
||||||
object SingletonCompileOnlySpec {
|
object SingletonCompileOnlySpec {
|
||||||
|
|
||||||
|
|
@ -39,7 +37,8 @@ object SingletonCompileOnlySpec {
|
||||||
val singletonManager = ClusterSingleton(system)
|
val singletonManager = ClusterSingleton(system)
|
||||||
// Start if needed and provide a proxy to a named singleton
|
// Start if needed and provide a proxy to a named singleton
|
||||||
val proxy: ActorRef[CounterCommand] = singletonManager.spawn(
|
val proxy: ActorRef[CounterCommand] = singletonManager.spawn(
|
||||||
behavior = counter("TheCounter", 0),
|
behavior = Behaviors.supervise(counter("TheCounter", 0))
|
||||||
|
.onFailure[Exception](SupervisorStrategy.restart),
|
||||||
"GlobalCounter",
|
"GlobalCounter",
|
||||||
Props.empty,
|
Props.empty,
|
||||||
ClusterSingletonSettings(system),
|
ClusterSingletonSettings(system),
|
||||||
|
|
@ -49,4 +48,14 @@ object SingletonCompileOnlySpec {
|
||||||
proxy ! Increment
|
proxy ! Increment
|
||||||
//#singleton
|
//#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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -160,7 +160,15 @@ with different settings if needed.
|
||||||
|
|
||||||
## Supervision
|
## 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
|
Scala
|
||||||
: @@snip [ClusterSingletonSupervision.scala](/akka-docs/src/test/scala/docs/cluster/singleton/ClusterSingletonSupervision.scala) { #singleton-supervisor-actor }
|
: @@snip [ClusterSingletonSupervision.scala](/akka-docs/src/test/scala/docs/cluster/singleton/ClusterSingletonSupervision.scala) { #singleton-supervisor-actor }
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,23 @@ Scala
|
||||||
Java
|
Java
|
||||||
: @@snip [SingletonCompileOnlyTest.java](/akka-cluster-typed/src/test/java/jdocs/akka/cluster/typed/SingletonCompileOnlyTest.java) { #import #singleton }
|
: @@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
|
## Accessing singleton of another data centre
|
||||||
|
|
||||||
TODO
|
TODO
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue