Skip to content

Clustering ​

Clustering turns a set of single-node actor systems into one cluster: actors spawn, are addressed, and are messaged by name across every node, without a caller knowing which machine an actor runs on. A node opens to its peers, its name registry is distributed across them, and an actor on any node reaches an actor on any other through its name alone.

It is built on three things the runtime already has, joined by one new directory:

  • Membership keeps every node's view of who is in the cluster, using a gossip protocol with failure detection.
  • A distributed registry shards the name → owning node directory across the cluster, so a lookup reads a name's record from whichever node owns that partition.
  • Remoting delivers tell, ask, request, watch, forward, and pipeTo to the owning node once its address is known.

One machine runs one logical actor system. A clustered node has a cluster identity (its data address) and an actor identity (its remoting address); it advertises the second in its membership metadata, so every node can map a cluster member to the endpoint its actors are reached at.

Example: examples/dns-actors, a three-node cluster discovered over DNS under Docker Compose, driven by an HTTP API, with a crash-and-recover drill. Run it with make actors.

Architecture ​

Each nodeActor treeClusterplacementMembershipRegistryshardRemotingOther nodesgossipsharded directoryactor messagesDiscoveryseeds at boot

Every node runs the same stack. The cluster placement is the layer this documentation is about: it wraps the actor tree and joins membership, the registry, and remoting so that spawning, addressing, and messaging work cluster-wide. Discovery seeds the node at boot; after that, the three fabrics (gossip membership, the sharded directory, and remoting) connect it to every peer.

Enable it ​

Clustering is a construction-time option, ClusterOptions. A clustered node must be reachable for actor messages, so remote is required alongside it: constructing a system with cluster set and no remote is a typed error (ErrClusterRequiresRemote), and a wildcard remoting host that peers cannot dial back is refused (ErrClusterRequiresRoutableHost).

ts
import { ActorSystem, DnsDiscovery, DnsRecordType } from "@tochemey/nodeakt";

const system = new ActorSystem("orders", {
  remote: { host: "0.0.0.0", advertisedHost: "node-a.svc", port: 4000 },
  cluster: {
    discovery: new DnsDiscovery({ hostname: "orders.svc", recordType: DnsRecordType.address, port: 7946 }),
    gossipPort: 7946,
  },
});

await system.start();
  • The node's remoting endpoint is its actor identity. Every local actor's path becomes nodeakt://orders@node-a.svc:4000/name, which is what other nodes use to reach it. Bind the wildcard host and set advertisedHost to the name peers resolve you by.
  • discovery is the one required cluster field: how the node finds seed peers at boot. Everything else defaults.
  • stop() leaves the cluster gracefully, then shuts the system down.

Every cluster call below rejects on a system created without a cluster configuration; spawn, actorOf, and the rest keep their single-node behavior.

The model ​

ConceptWhat it means
Cluster-unique namesA top-level actor name is unique across the whole cluster. spawn("orders") on one node and spawn("orders") on another race for the name; the loser is refused with ErrActorAlreadyExists.
Placementspawn keeps an actor local. spawnOn places it on the node a strategy chooses. Either way the name → node record goes in the distributed registry.
SingletonsspawnSingleton gives a name exactly one live instance cluster-wide, pinned to the coordinator, idempotent to create.
Location-transparent messagingactorOf and actorOfAsync return a PID that routes to the owning node, wherever it runs. tell, ask, watch, and the rest keep their call sites.
RelocationWhen a node departs, gracefully or by crash, the coordinator recreates its relocatable actors on the survivors from their stored recipes.
Eventssubscribe delivers membership and relocation events (NodeJoined, NodeLeft, RelocationCompleted, and friends).

What clustering is not ​

  • Not a persistence layer. The framework stores no actor state on disk, ever. A relocated actor is rebuilt from its recipe and recovers its own state in preStart; see relocation.
  • Not authorized. The trust model is a private network whose nodes trust each other, exactly as remoting describes. Do not expose a gossip, data, or remoting port to an untrusted network.
  • Not a message-delivery guarantee across a move. Messages in flight when an actor relocates are lost; the actor's identity and configuration come back, its in-flight mailbox does not.

Released under the MIT License.