Skip to main content
A cluster singleton is an actor with exactly one instance per name across the entire cluster. It is hosted on the cluster coordinator (oldest node). When that host node leaves the cluster gracefully, the singleton is recreated on the new coordinator. Singleton identity is the actor name: several singletons of the same actor kind can coexist under different names. A role, when set, only filters which nodes can host the singleton; it is not part of its identity.

Singletons vs normal actors

When to use singletons

  • Cluster-wide coordinator: Job scheduler, leader election, or coordination that must run once across the cluster
  • Single source of truth: Centralized state or registry that must be unique (e.g. license manager, cluster metadata)
  • Exclusive resource: A resource that must have exactly one owner (e.g. distributed lock coordinator)

When to use normal actors

  • Scalable workers: Many instances for parallelism (e.g. request handlers, workers)
  • Per-entity or per-request: One actor per user, session, or task
  • Explicit lifecycle: You control when to spawn and stop
  • Standalone or local-only: No cluster, or node-local state

Requirements

  • Cluster mode: Singletons require clustering. SpawnSingleton returns ErrClusterDisabled when cluster mode is off.
  • Remoting: Clustering requires remoting; the singleton may run on a different node than the caller.
  • Actor kind registered: The actor type must be registered via WithKinds when creating the actor system.

API

Use ActorOf(ctx, name) to resolve the singleton from any node. Messaging is location-transparent: Tell and Ask work the same whether the singleton is local or remote. From inside Receive, use ctx.Request(pid, msg, opts...) for non-blocking request-response.

Placement

  • Default: The singleton runs on the cluster coordinator (oldest node by membership).
  • With role: Use WithSingletonRole(role) to pin the singleton to nodes that advertise that role. The oldest node with the role (by CreatedAt) hosts it. If no node has the role, SpawnSingleton retries according to the spawn options; it returns an error only after retries are exhausted or the spawn timeout elapses.

Configuration options

Example with role:

Supervision

By default a singleton uses a dedicated supervisor with a OneForOne strategy that stops the actor on panics and internal errors, leaving recovery to the relocation machinery. The actor system’s WithDefaultSupervisor fallback does not apply to singletons. Use WithSingletonSupervisor to override this behavior. The supervisor applies on whichever node hosts the singleton: it travels with the spawn request when placement is delegated to another node, and it is restored when the singleton is relocated after its host leaves the cluster.
A RestartDirective restarts the singleton in place on its current host; it does not trigger a relocation. Relocation still happens when the host node leaves the cluster.

Idempotency

Calling SpawnSingleton again with the same name and actor kind is idempotent: the call succeeds and returns the existing singleton’s PID. Concurrent calls from several nodes converge to a single instance. When the name is already used by a different actor (or a singleton of a different kind), SpawnSingleton returns ErrActorAlreadyExists.

Relocation

When the host node leaves the cluster gracefully, the relocator recreates the singleton on the new coordinator. See Relocation for the full flow. If the host node crashes (kill -9, OOM, etc.), relocation does not run; the singleton is lost until SpawnSingleton is called again for that name.

Lifecycle

  • A singleton lives for the lifetime of the actor system. It is supervised by the default singleton supervisor unless WithSingletonSupervisor is provided; see Supervision.
  • It is not passivated by default; use WithPassivationStrategy if you need idle-based deactivation (uncommon for singletons).
  • Use pid.IsSingleton() to check whether a PID is a cluster singleton.

Errors

ErrSingletonAlreadyExists is deprecated. It is only returned when the spawn is handled by a cluster node running an older version of GoAkt during a rolling upgrade.

See also