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.
SpawnSingletonreturnsErrClusterDisabledwhen 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
WithKindswhen creating the actor system.
API
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 (byCreatedAt) hosts it. If no node has the role,SpawnSingletonretries 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’sWithDefaultSupervisor 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
CallingSpawnSingleton 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 untilSpawnSingleton 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
WithSingletonSupervisoris provided; see Supervision. - It is not passivated by default; use
WithPassivationStrategyif 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
- Actor System:
SpawnSingletonin the spawn methods table - Clustering: Cluster setup
- Relocation: How singletons are relocated when nodes leave