Skip to main content

API reference

This is a structured reference of the public surface of Clustron.Nodus.Client and Clustron.Nodus.Abstractions, organized by area. Each area lists its members as signature plus a one-line description. For narrative walkthroughs, follow the links into the Developer guide.

Everything hangs off a single running handle, INodusNode, obtained from the NodusNode entry point.

Entry point: NodusNode

static class NodusNode is the one way in. It either starts a node directly or hands you a fluent builder.

public static class NodusNode
{
// Join the cluster with a default container and return a running node.
static Task<INodusNode> StartAsync(NodusConfig config, NodeInfo self, CancellationToken ct = default);

// Begin a fluent build for custom services, identity, or overrides.
static NodusNodeBuilder Configure(NodusConfig config);
}
MemberSignatureDescription
StartAsyncTask<INodusNode> StartAsync(NodusConfig config, NodeInfo self, CancellationToken ct = default)Shorthand for Configure(config).WithNodeIdentity(self).StartAsync(ct).
ConfigureNodusNodeBuilder Configure(NodusConfig config)Returns a NodusNodeBuilder for the fluent path.

NodusNodeBuilder

public sealed class NodusNodeBuilder
{
NodusNodeBuilder WithNodeIdentity(NodeInfo self); // required
NodusNodeBuilder WithServices(IServiceCollection services);
NodusNodeBuilder WithConfiguration(IConfiguration fullConfig);
NodusNodeBuilder WithOverrides(Action<NodusConfig> overrides);
Task<INodusNode> StartAsync(CancellationToken ct = default);
}
MemberDescription
WithNodeIdentity(self)Which node in the cluster this process is. Required — omitting it throws InvalidOperationException.
WithServices(services)Compose into an existing container instead of a fresh one.
WithConfiguration(fullConfig)Supply the full IConfiguration for env/CLI overrides.
WithOverrides(overrides)Mutate the NodusConfig in place before the node is built.
StartAsync(ct)Build the container, start the node, and return the running INodusNode.

See Building a node.

The node handle: INodusNode

INodusNode is IAsyncDisposable. It carries the node's identity and lifecycle plus the six capability areas.

public interface INodusNode : IAsyncDisposable
{
string NodeId { get; }
bool IsRunning { get; }

Task StartAsync(CancellationToken cancellationToken = default);
Task StopAsync(CancellationToken cancellationToken = default);

IClusterMembership Cluster { get; }
ILeadership Leadership { get; }
IMessaging Messaging { get; }
IClusterEvents Events { get; }
IClusterHealth Health { get; }
IClusterGossip Gossip { get; }
IServiceProvider Services { get; }
}
MemberDescription
NodeIdThis node's stable id.
IsRunningtrue once started and not yet stopped.
StartAsync(ct)Join the cluster and begin serving. Idempotent.
StopAsync(ct)Leave the cluster gracefully and tear down transport.
ClusterMembership and topology (IClusterMembership).
LeadershipLeadership (ILeadership).
MessagingPoint-to-point, broadcast, and request/reply (IMessaging).
EventsTyped cluster-wide pub/sub (IClusterEvents).
HealthHealth and metrics (IClusterHealth).
GossipHeartbeat gossip plane (IClusterGossip).
ServicesThe underlying DI container. Prefer the areas above.
DisposeAsync()Stops the node if running (from IAsyncDisposable).

Membership: IClusterMembership (node.Cluster)

Who is in the cluster right now — live, reachable, by role — and join/leave events. See Membership.

public interface IClusterMembership
{
ClusterNode Self { get; }
IReadOnlyList<ClusterNode> Members { get; }
ClusterNode? Find(string nodeId);
bool IsAlive(string nodeId);
DateTime? LastHeartbeatUtc(string nodeId);
bool IsReachable(string nodeId);
IReadOnlyList<string> ReachableNodeIds { get; }
IEnumerable<ClusterNode> MembersInRole(string role);
void RegisterKnownPeer(ClusterNode node);
bool IsStaleLeave(ClusterNode node);

event Action<ClusterNode> MemberJoined;
event Action<ClusterNode> MemberLeft;
}
MemberDescription
SelfThis node as a ClusterNode.
MembersCurrent active members, excluding self.
Find(nodeId)A member by id, or null.
IsAlive(nodeId)true once we have received from the peer (it is live).
LastHeartbeatUtc(nodeId)UTC of the last heartbeat from the peer; null if never or self.
IsReachable(nodeId)true when we can dial the peer (outbound connect succeeded). O(1).
ReachableNodeIdsIds currently confirmed reachable, independent of liveness.
MembersInRole(role)Members advertising the given role.
RegisterKnownPeer(node)Register a known peer so it can be dialed before admission.
IsStaleLeave(node)true when a departure notice is obsolete (node already rejoined at a newer generation).
MemberJoinedRaised when a node joins active membership.
MemberLeftRaised when a node leaves active membership.

Leadership: ILeadership (node.Leadership)

Who leads this epoch, and control over it. See Leader election.

public interface ILeadership
{
ClusterNode? Current { get; }
bool IsSelf { get; }
int Epoch { get; }
void SetTiebreaker(Func<(int nodeCount, long createdAtTicks)> localBacking);
event Action<ClusterNode, int> Changed;
}
MemberDescription
CurrentThe current leader, or null when there is none.
IsSelftrue when this node is the current leader.
EpochThe current election epoch.
SetTiebreaker(localBacking)Supply this node's (nodeCount, createdAtTicks) backing for the equal-epoch tiebreaker.
ChangedRaised when leadership changes; carries (newLeader, epoch).

Messaging: IMessaging (node.Messaging)

Directed communication: typed convenience plus full wire control, including request/reply. See Messaging, Sending messages, and Request/reply.

public interface IMessaging
{
// typed convenience
Task SendAsync<T>(string nodeId, T payload);
Task BroadcastAsync<T>(T payload);
void On<T>(Func<T, string, Task> handler);

// protocol-level (full wire control)
Message CreateMessage<T>(string messageType, T payload);
Task SendAsync(string nodeId, Message message);
Task SendImmediateAsync(string nodeId, Message message);
Task<TReply?> RequestAsync<TReply>(string nodeId, Message message, TimeSpan? timeout = null);
Task AddHandler(IMessageHandler handler);
}
MemberDescription
SendAsync<T>(nodeId, payload)Send a typed payload to a specific node.
BroadcastAsync<T>(payload)Send a typed payload to every member.
On<T>(handler)Register a typed handler receiving (payload, fromNodeId). See the caveat below.
CreateMessage<T>(type, payload)Build a wire Message stamped with this node's id and serializer, and a fresh correlation id.
SendAsync(nodeId, message)Send a pre-built wire message on the queued path.
SendImmediateAsync(nodeId, message)Send on the unbuffered/priority plane.
RequestAsync<TReply>(nodeId, message, timeout?)Send and await a typed reply; throws TimeoutException on timeout. Default timeout is 50 s.
AddHandler(handler)Register a low-level IMessageHandler on the router (dispatched by message type).
One typed handler per node

On<T> registers into a single typed-message slot — every call maps to the same underlying client-message channel, so a later On<T> replaces the earlier one. A node has one typed handler at a time. Use a single envelope type with a discriminator field and branch inside the handler, or drop to AddHandler with distinct IMessageHandler.Type values for genuinely separate handlers. See Sending messages.

Cluster events: IClusterEvents (node.Events)

Typed publish/subscribe, distinct from direct messaging. See Cluster events and Subscribing to events.

public interface IClusterEvents
{
Task PublishAsync<T>(T @event, EventDispatchOptions? options = null) where T : IClusterEvent;
void Subscribe<T>(Func<T, Task> handler) where T : IClusterEvent;
void Subscribe<TEvent, TPayload>(Func<TEvent, Task> handler)
where TEvent : CustomClusterEvent<TPayload>, new();
}
MemberDescription
PublishAsync<T>(event, options?)Publish a typed cluster event; optional EventDispatchOptions control delivery. Requires the member role and throws NotSupportedException otherwise.
Subscribe<T>(handler)Subscribe to a typed cluster event (built-in lifecycle events or IClusterEvent types).
Subscribe<TEvent, TPayload>(handler)Subscribe to a CustomClusterEvent<TPayload>.

Health: IClusterHealth (node.Health)

Health of this node, its peers, and the cluster. See Health and gossip and Health and membership.

public interface IClusterHealth
{
NodeHealthStatus Local { get; }
IReadOnlyList<NodeHealthStatus> Peers { get; }
ClusterMetrics Metrics { get; }
}
MemberDescription
LocalHealth of this node (NodeHealthStatus).
PeersHealth of each known peer.
MetricsCluster-level metrics (ClusterMetrics).
node.Health is a minimal snapshot in the current release

The current adapter reports Local.IsAlive == true with LastSeenUtc == now, derives peer liveness from live membership, and populates ClusterMetrics.ActivePeers. TotalMessagesSent and AvgLatencyMs are model fields the adapter does not yet fill in. For live liveness, prefer node.Cluster.IsAlive and node.Cluster.LastHeartbeatUtc.

Gossip: IClusterGossip (node.Gossip)

Ride your own state digest on the heartbeat plane. See Health and gossip.

public interface IClusterGossip
{
void SetDigestProvider(IClusterStateDigestProvider provider);
event Action<string, ClusterStateDigest> DigestReceived;
}
MemberDescription
SetDigestProvider(provider)Attach a provider whose digest rides on every outbound heartbeat.
DigestReceivedRaised when a peer's digest arrives; carries (fromNodeId, digest).

Key types

NodeInfo

A node's declared identity (see Configuration for defaults).

PropertyTypeNotes
NodeIdstringStable, unique id / join key.
HoststringDial address peers use.
PortintCluster TCP port this node binds.
ClusterIdstringMust match the cluster.
VersionstringNode version tag.
RolesList<string>Advertised roles.
MetadataDictionary<string,string>Free-form.
MachineIdstring?Physical-machine grouping (higher-layer placement).
IsPreferredPrimaryboolPlacement hint (higher layers).
StartedAtTickslongProcess-start marker; drives oldest-node election.

ClusterNode

The runtime shape of a member, returned by membership APIs and events.

PropertyType
NodeIdstring
Hoststring?
Portint
ClusterIdstring
RolesIReadOnlyList<string>
MetadataDictionary<string,string>

Message: the wire envelope

PropertyTypePurpose
MessageTypestringRouting key handlers register against.
SenderIdstringStamped by CreateMessage.
CorrelationIdstring?Ties a reply back to its request.
TraceParentstring?W3C traceparent for cross-node tracing.
TypeInfostringAssembly-qualified payload type name.
Payloadbyte[]MessagePack-serialized payload.
TimestampDateTimeSend time (UTC).

IMessageHandler

Low-level handler registered via Messaging.AddHandler.

public interface IMessageHandler
{
string Type { get; }
Task HandleAsync(Message rawMessage);
MessageDispatchMode DispatchMode { get; }
}
MemberDescription
TypeThe MessageType this handler is dispatched for.
HandleAsync(rawMessage)Handle the raw wire message.
DispatchModeHow the router runs it (see the enum below).

Health models

public class NodeHealthStatus
{
string NodeId; bool IsAlive; DateTime LastSeenUtc; IEnumerable<string> Roles;
}

public class ClusterMetrics
{
int TotalMessagesSent; int ActivePeers; double AvgLatencyMs;
}

Enums and options

ElectionStrategyKind

ValueNumericWinner
HighestId0Highest NodeId.
OldestNode1Smallest non-zero StartedAtTicks.

ElectionOptions

PropertyTypeDefault
StrategyElectionStrategyKindOldestNode (the XML comment says HighestId; the code default is OldestNode).

MessageDispatchMode

ValueMeaning
InlineAwaited inline on the receive loop — fast, non-blocking handlers.
FastPathSubmitted to the priority fast path — critical control messages.
DataPathSubmitted to the data dispatcher — heavy handlers.

EventDispatchOptions

PropertyTypeDefault
PolicyDispatchPolicyFireAndForget
MaxRetryAttemptsint3
RetryDelayMillisecondsint200
ScopeDeliveryScopeClusterWide
  • DispatchPolicy: FireAndForget, Ordered, Parallel, Retry.
  • DeliveryScope: LocalOnly, ClusterWide.
  • ClusterEventScope (on IClusterEvent): LocalOnly, ClusterWide.

NodusRoles

SendAsync, BroadcastAsync, and PublishAsync throw NotSupportedException from a node without the member role, and election considers only members.

ConstantValueMeaning
NodusRoles.Member"member"Full cluster participant — elects, is elected, sends, receives.
NodusRoles.Observer"observer"Lifecycle and leader-change only.
NodusRoles.MetricsCollector"metrics-collector"Actively polls metrics.
NodusRoles.Client"client"Sends requests, no cluster awareness.

Events and event types

Built-in cluster events

All derive from ClusterEventBase<T> (whose Scope is ClusterWide) and implement IClusterEvent.

TypeKey members
NodeJoinedEventNode (NodeInfo), Incarnation (int)
NodeLeftEventNode (NodeInfo), Incarnation (int)
LeaderChangedEventNewLeader (NodeInfo), Epoch (int)
NodeRestartedEventNode (NodeInfo), Generation (long)

CustomClusterEvent<T>

For your own payloads. Derives from ClusterEventBase<T>.

MemberTypePurpose
PayloadTYour payload.
Publisherstring?Optional publishing-node id.
MetadataDictionary<string,string>?Optional tags.
TimestampDateTimeEvent time (from the base).

IClusterEvent

public interface IClusterEvent
{
ClusterEventScope Scope { get; }
string EventType { get; }
}

IClusterStateDigestProvider and ClusterStateDigest

public interface IClusterStateDigestProvider
{
ClusterStateDigest GetCurrentDigest();
}

ClusterStateDigest is a compact summary — epoch, leader id, map version and node count, and optional per-partition generation maps — attached to every heartbeat for passive drift detection. Keep it small. See Health and gossip.

Packages

PackageTargetContains
Clustron.Nodus.Abstractionsnetstandard2.0NodeInfo, ClusterNode, Message, NodusConfig, ElectionOptions, events, and other contracts.
Clustron.Nodus.Clientnet8.0NodusNode, INodusNode, the six area interfaces, and the runtime. Depends on Clustron.Nodus.Core.

Next steps