Clustering and coordination, without a coordinator to run
Nodus is a lightweight clustering and messaging core that lets your service join a peer-to-peer cluster, agree on a leader, exchange typed messages, and detect failures — with no external coordinator like ZooKeeper, etcd, or Consul to stand up, secure, or keep alive. It is a library you embed, so the cluster forms and heals itself.
The hard parts of running more than one instance — solved and embedded
The moment your app runs as more than one process, membership, coordination, messaging, and failure detection become distributed-systems problems. Nodus ships all four in a single dependency that runs inside your process.
Peer-to-peer membership
Nodes discover and admit each other from a static or dynamic peer set. Joins and leaves surface as events, with no registry service to operate.
Leader election
Deterministic bully-style strategies — highest-id or oldest-node — with an epoch counter and a tiebreaker for equal-epoch collisions, so the cluster agrees on exactly one coordinator.
Typed messaging
Send a typed payload point-to-point, broadcast to every member, or drop to the raw wire message for correlation ids and the priority plane.
Request / reply
Ask one node a question and await a typed answer, matched by correlation id, with a timeout you control.
Cluster-wide events
A typed publish/subscribe bus, distinct from direct messaging, that propagates lifecycle and custom events across every member.
Health & failure detection
Heartbeats, per-peer reachability, and a suspicion window keep membership honest — telling "slow" from "gone" without flapping — and a gossip digest rides the same traffic.
Nodes agree — even as the cluster changes shape
Every member runs the same deterministic election over the same reachable peers, so they independently pick the same leader without a multi-round vote. When a node joins or the leader fails, the survivors re-elect and the epoch advances — so a stale leader can always be told from the current one.
- A single entry point builds the container, joins the cluster, and returns a running handle.
- Leader loss is detected fast on a graceful leave, or after the suspicion window on a hard kill.
- Each survivor computes the same new leader and the epoch increments.
- Disposal leaves the cluster cleanly so peers evict promptly and failover is quick.
Wherever a set of processes must agree
Reach for Nodus whenever your service runs as more than one instance and needs to coordinate — and it works with your app today.
Build cluster-aware services
Give any multi-instance service a live view of its peers, a shared leader, and a way to message members directly — the foundation Zaris itself clusters on.
Leader-only singletons & schedulers
Run a cron-like job on exactly one instance, gated on IsSelf, and have a survivor take over automatically at a higher epoch when the leader fails.
Failure detection & self-healing membership
Heartbeats and a suspicion window evict dead peers and admit new ones, keeping the cluster accurate through crashes and restarts.
Typed messaging & request-reply
Address a specific peer, send it work, and await a typed answer — or broadcast to everyone — over a persistent, prioritized transport.
Cache & peer invalidation
Broadcast an eviction to every member the instant a value changes, so no instance serves a stale entry.
Work distribution across nodes
Let a coordinator fan chunks of work across live members and aggregate the results — exactly what the shipped cluster-coordination sample does.
Join a cluster and follow the leader
One entry point builds the node, joins the cluster, and returns a running handle. Subscribe to leadership and gate singleton work on the node that leads.
Read the docsusing Clustron.Nodus.Abstractions;
using Clustron.Nodus.Client;
// this process's slice of the cluster, resolved from a launch input
var self = config.Cluster.Nodes.Single(n => n.NodeId == myId);
await using INodusNode node = await NodusNode
.Configure(config)
.WithNodeIdentity(self)
.StartAsync();
// react the moment the cluster agrees on a coordinator
node.Leadership.Changed += (leader, epoch) =>
Console.WriteLine($"leader is now {leader.NodeId} (epoch {epoch})");
// run the singleton only where we lead
if (node.Leadership.IsSelf)
await RunTheSingletonJob();
Ready to build with Nodus?
Get started in minutes, or talk to us about your architecture.