Cluster Singleton

For some use cases it is convenient and sometimes also mandatory to ensure that you have exactly one actor of a certain type running somewhere in the cluster.

Some examples:

  • single point of responsibility for certain cluster-wide consistent decisions, or coordination of actions across the cluster system
  • single entry point to an external system
  • single master, many workers
  • centralized naming service, or routing logic

Using a singleton should not be the first design choice. It has several drawbacks, such as single-point of bottleneck. Single-point of failure is also a relevant concern, but for some cases this feature takes care of that by making sure that another singleton instance will eventually be started.

Warning

This module is currently marked as may change in the sense of being the subject of active research. This means that API or semantics can change without warning or deprecation period and it is not recommended to use this module in production just yet—you have been warned.

Dependency

To use Akka Cluster Singleton Typed, add the module to your project:

sbt
libraryDependencies += "com.typesafe.akka" %% "akka-cluster-typed" % "2.5.11"
Maven
<dependency>
  <groupId>com.typesafe.akka</groupId>
  <artifactId>akka-cluster-typed_2.12</artifactId>
  <version>2.5.11</version>
</dependency>
Gradle
dependencies {
  compile group: 'com.typesafe.akka', name: 'akka-cluster-typed_2.12', version: '2.5.11'
}

Example

Any Behavior can be run as a singleton. E.g. a basic counter:

Scala
import akka.cluster.sharding.typed.ClusterShardingSettings
import akka.cluster.sharding.typed.ShardingEnvelope
import akka.cluster.sharding.typed.scaladsl.ClusterSharding
import akka.cluster.sharding.typed.scaladsl.EntityTypeKey
import akka.cluster.sharding.typed.scaladsl.EntityRef

val sharding = ClusterSharding(system)
Java
ClusterSharding sharding = ClusterSharding.get(system);

Then on every node in the cluster, or every node with a given role, use the ClusterSingleton extension to spawn the singleton. Only a single instance will run in the cluster:

Scala
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),
  "GlobalCounter",
  Props.empty,
  ClusterSingletonSettings(system),
  terminationMessage = GoodByeCounter
)

proxy ! Increment
Java
ClusterSingleton singleton = ClusterSingleton.get(system);
// Start if needed and provide a proxy to a named singleton
ActorRef<CounterCommand> proxy = singleton.spawn(
  counter("TheCounter", 0),
  "GlobalCounter",
  Props.empty(),
  ClusterSingletonSettings.create(system),
  new GoodByeCounter()
);

proxy.tell(new Increment());
Found an error in this documentation? The source code for this page can be found here. Please feel free to edit and contribute a pull request.