Role and responsibilities
- Actor hosting: Spawns and supervises actors under the
/userguardian. Manages the actor tree and parent-child relationships. - Messaging: Routes messages locally or remotely. Serializes and deserializes when crossing node boundaries.
- Clustering: When enabled, joins a cluster, discovers peers, and provides location-transparent actor resolution.
- Remoting: When enabled, exposes a TCP server and client for cross-node communication.
- Event stream: Publishes system and cluster events (ActorStarted, NodeJoined, Deadletter, etc.) to subscribers. See Event Streams.
- PubSub: When
WithPubSubor cluster is enabled, a topic actor manages application-level topics. See PubSub. - Scheduling: Delivers one-time, recurring, and cron-scheduled messages to actors.
- Coordinated shutdown: Runs shutdown hooks, stops actors depth-first, and leaves the cluster gracefully.
Lifecycle
Lifecycle
- NewActorSystem: Applies options; does not start services.
- Start: Initializes remoting (if enabled), cluster (if enabled), scheduler, eviction, passivation, and system
actors. Handle SIGTERM/SIGINT and call
Stopfor clean shutdown. - Stop: Runs coordinated shutdown hooks, stops user actors, deactivates grains, shuts down system actors, leaves
cluster, stops remoting. Does not exit the process; call
os.Exitif needed.
API surface
Spawning
- Spawn: Create a named actor locally (or on a specific host with
WithHostAndPort). - SpawnOn: Create actor on a cluster node (see Placement) or in another data center
(
WithDataCenter). - SpawnFromFunc: Functional actor; no
Actorimplementation. - SpawnNamedFromFunc: Named functional actor.
- SpawnRouter: Router with a pool of routees. Not cluster-relocatable.
- SpawnSingleton: Cluster singleton; one instance per name across the cluster, hosted on the oldest node. See Singletons.
ErrActorAlreadyExists, and when several nodes spawn the same name at the same time, one spawn succeeds. A child’s
name is unique within its parent. See Placement.
See Actor Lifecycle, Routers, Singletons,
Clustering.
Resolution and inspection
- ActorOf: Resolve a PID by name. Local or remote; use
pid.IsLocal/pid.IsRemotewhen it matters. - ActorExists: Check if an actor exists locally or in the cluster.
- Actors: Enumerate all actors visible to this node. Use sparingly; cluster scan is costly.
- NumActors: Count of local actors only.
- Partition: Partition ID for a given actor name (cluster hashing).
- InCluster: Whether the system is running in cluster mode.
Messaging from outside
From outside the actor system (e.g.main), use system.NoSender():
- NoSender().Tell(pid, msg): Fire-and-forget.
- NoSender().Ask(ctx, pid, msg, timeout): Request-response; actor must call
ctx.Response(resp).
Scheduling
- ScheduleOnce: One-time delivery after
delay. - Schedule: Recurring delivery at
interval. - ScheduleWithCron: Cron-based delivery.
- CancelSchedule: Cancel by reference.
- PauseSchedule / ResumeSchedule: Pause or resume a scheduled task.
WithReference(id) when scheduling if you need to cancel, pause, or resume. See Scheduling.
Events and observability
- Subscribe: Create an event-stream subscriber for system/cluster events. Returns
eventstream.Subscriber; iterate viaIterator. - Unsubscribe: Release subscriber; call to avoid leaks.
- TopicActor: Topic actor PID for PubSub (when
WithPubSubor cluster is enabled). Send Subscribe, Unsubscribe, Publish. - Metric: Node-level metrics (actor count, mailbox sizes, throughput, uptime).
Cluster and lifecycle control
- Kill: Stop an actor by name (local or remote).
- ReSpawn: Restart an actor with its whole subtree. The same actor values are reused and only
PreStartruns again, so state thatPreStartdoes not reset survives the restart. - Name: Actor system name.
Dependency injection
- Inject: Register dependency types with the actor system after startup. Enables restoration during cluster topology
changes and when creating actors on remote hosts. Must be called after
Start.
Configuration options
Options are passed toNewActorSystem(name, opts...). Each option is documented in the source; they are grouped here by
concern.
-
Core
- WithLogger: Custom logger.
WithLoggingDisabledfor no-op. - WithActorInitTimeout: Actor startup timeout.
- WithActorInitMaxRetries: Retries for actor init.
- WithShutdownTimeout: Total shutdown timeout (default: 3 min).
- WithAskTimeout: System-wide timeout for internal Ask round-trips (default: 5s).
- WithDefaultSupervisor: Fallback supervisor for actors without explicit config.
- WithLogger: Custom logger.
-
Remoting & cluster
- WithRemote: Enable remoting. See Remoting.
- WithCluster: Enable clustering. See Clustering.
- WithTLS: Deprecated: use
remote.WithTLSon the remote config. See TLS. - WithoutRelocation: Disable actor relocation on node departure.
-
Extensions & capabilities
- WithExtensions: System-wide extensions. See Extensions and Dependencies.
- WithPubSub: Enable topic-based pub/sub.
- WithMetrics: OpenTelemetry metrics. See Observability.
-
Shutdown & eviction
- WithCoordinatedShutdown: Shutdown hooks. See Coordinated Shutdown.
- WithEvictionStrategy: Passivation when actor count exceeds limit.
-
Advanced
- WithThroughputBudget: Messages an actor may process per scheduler turn (default: 32). See Throughput budget for tuning profiles.
- WithDispatcherPoolSize: Size of the worker pool that runs actor and grain turns (default:
max(GOMAXPROCS, 2)), for handlers that block in their turn. See Worker pool size for the trade-off. - WithPartitionHasher: Deprecated: use
ClusterConfig.WithPartitionHasher. See Partition Hashing.
Tuning the dispatcher
Actors and grains do not own goroutines. EachActorSystem runs them on one fixed pool of worker goroutines, the
dispatcher. A worker takes an actor that has messages, handles up to a budget of them in one turn, and then moves on so
other actors get a turn. runtime.NumGoroutine() therefore stays near the worker count however many actors are active.
Two options tune the dispatcher. Neither changes the guarantees your code relies on: an actor or grain still handles one
message at a time, and messages from one sender to one actor still arrive in the order they were sent.
Throughput budget
WithThroughputBudget sets how many messages a worker handles from one actor before it yields to the next. The default
of 32 favors fairness and predictable tail latency. A larger budget spreads the cost of scheduling over more messages
and keeps a busy actor’s state in the CPU caches, which raises aggregate throughput. The cost is fairness: a busy actor
holds its worker longer before its peers get a turn.
Tuning the throughput budget
- 8 to 16: latency-critical systems with many small actors, such as control planes and request routing.
- 32 (default): a balanced setting for most mixed workloads.
- 64: a safe upgrade for throughput-oriented systems, typically 5 to 15% more aggregate throughput on message-heavy workloads.
- 128: ingest and aggregation, such as log pipelines, event firehoses and batch processors.
- 256 and above: synthetic benchmarks or a single hot actor only. Throughput flattens and tail latency grows.
Worker pool size
The pool defaults tomax(GOMAXPROCS, 2) workers, one per OS thread, which is right for handlers that compute and
return. A handler that blocks in its turn, on a database call or a synchronous request, holds its worker for the whole
wait. With the default pool, no more than GOMAXPROCS actors and grains make progress at once, whatever their number:
on a two-CPU container, two. WithDispatcherPoolSize sets the pool size for the system:
Sizing the worker pool
WithDispatcherPoolSize(256), on an 8-CPU Apple M1 with GOMAXPROCS=8, five runs each. These handlers do not
block, so the numbers are the pure dispatch cost of the larger pool. Per-actor and per-grain heap did not change.
Request/reply pays the most because every round trip wakes a parked worker, and with a large pool that is usually a
cold one. Plain tells to a busy actor are unaffected: the worker never parks.
The gain on the other side is what the option exists for. With 200 grains that each wait 10 ms in their turn, five
messages each and all 1000 asks in flight, a node with
GOMAXPROCS=2 takes 5.5 s with the default pool and 53 ms with
256 workers, because the 200 grains wait at the same time instead of two at a time.
How the dispatcher is built (its ready queue, work stealing and the state machine that keeps one actor on one worker) is
covered in chapter 7 of the maintainers’ book.
Component relationships
The ActorSystem composes:- Remoting: TCP server/client; used when
WithRemoteis set. - Cluster: Membership, discovery, Olric DMap; used when
WithClusteris set. - Event stream: In-process pub/sub; always present; topic actors when
WithPubSubis set. - Scheduler: For
ScheduleOnce,Schedule,ScheduleWithCron. - Extensions: Accessed via
ctx.Extension(id)from actors.
ctx.ActorSystem() (or ReceiveContext, GrainContext). Use it to spawn children,
resolve actors, schedule, or access extensions. Do not store the ActorSystem in actor state; always obtain it from
context.
Further reading
- Quickstart: Minimal flow
- Actor Model: Actor interface and hierarchy
- Clustering: Standalone vs clustered vs multi-DC
- Reference: Interfaces: Interface definitions