Malachi. Consumer. CoordinatorRouter
(malachi v0.22.7)
View Source
Routes a topic's consumer-group coordination to a single owning node, so every member of a group:
connected to any broker: reaches the same GroupCoordinator. The invariant "each range under
exactly one member" needs one coordination authority per topic; with a local coordinator per node,
members on different nodes would see divergent assignments.
Mirrors NorthGuard's request routing: a broker consults its local view of the sharded metadata (the
HashRing over vnodes) to find the vnode that owns the topic, then forwards to the node currently
leading that vnode's Raft cluster (the owner co-locates with the topic's metadata, so the
coordinator's active_range_ids/2 resolves against the local broker).
Single-node / in-memory has no sharded control plane → no topology → everything is :local, so the
behavior is exactly the pre-routing one. The routing decision is a pure function (location/4) with
the topology and live leadership passed in; resolve/2 is the thin runtime wrapper that reads the
boot-published topology (:persistent_term) and the current Raft leader.
Summary
Functions
The per-vnode coordinator name derived from a base_name and a vnode_id. In the sharded control plane
each led vnode runs its own GroupCoordinator (one per vnode, on the leader: the NorthGuard model), so
routing and the boot wiring must agree on this name.
Decides where a topic's coordination lives. Returns :local when this node owns the topic's vnode:
and, fail-safe, whenever there is no topology, the ring can't route, the vnode is unknown, or its
leader can't be resolved (a resolution gap degrades to the local coordinator rather than dropping the
request). Returns {:remote, node} when another node leads the owning vnode. leader_fn maps a
vnode's server id to the node currently leading it (or nil if unknown).
Whether this node owns topic's coordination (it leads the topic's vnode, or there is no sharded
topology). The owning coordinator uses this to reject work routed to it by a stale leadership view.
Publishes the static routing topology (the ring + vnode→server-id map) for resolve/2. Called once at
boot when the sharded control plane is established; unset means single-node / in-memory.
Turns a location/4 result into a coordinator GenServer.server() ref ({name, node} if remote).
Resolves the coordinator ref for topic. Single-node / in-memory (no topology): the bare base_name.
Sharded: the topic's vnode owns a per-vnode coordinator on its leader, coordinator_name/2 locally
when this node leads it, or {coordinator_name/2, owner_node} to forward. Falls back to base_name when
the owning vnode or its leader can't be resolved (a transient failover state; the caller re-resolves).
The current routing topology, or nil in single-node / in-memory mode (no sharded control plane).
Types
@type location() :: :local | {:remote, node()}
@type topology() :: %{ ring: Malachi.Cluster.HashRing.t(), servers: %{required(term()) => term()} }
Functions
The per-vnode coordinator name derived from a base_name and a vnode_id. In the sharded control plane
each led vnode runs its own GroupCoordinator (one per vnode, on the leader: the NorthGuard model), so
routing and the boot wiring must agree on this name.
Decides where a topic's coordination lives. Returns :local when this node owns the topic's vnode:
and, fail-safe, whenever there is no topology, the ring can't route, the vnode is unknown, or its
leader can't be resolved (a resolution gap degrades to the local coordinator rather than dropping the
request). Returns {:remote, node} when another node leads the owning vnode. leader_fn maps a
vnode's server id to the node currently leading it (or nil if unknown).
Whether this node owns topic's coordination (it leads the topic's vnode, or there is no sharded
topology). The owning coordinator uses this to reject work routed to it by a stale leadership view.
@spec put_topology(Malachi.Cluster.HashRing.t(), %{required(term()) => term()}) :: :ok
Publishes the static routing topology (the ring + vnode→server-id map) for resolve/2. Called once at
boot when the sharded control plane is established; unset means single-node / in-memory.
@spec ref(location(), atom()) :: GenServer.server()
Turns a location/4 result into a coordinator GenServer.server() ref ({name, node} if remote).
@spec resolve(atom(), term()) :: GenServer.server()
Resolves the coordinator ref for topic. Single-node / in-memory (no topology): the bare base_name.
Sharded: the topic's vnode owns a per-vnode coordinator on its leader, coordinator_name/2 locally
when this node leads it, or {coordinator_name/2, owner_node} to forward. Falls back to base_name when
the owning vnode or its leader can't be resolved (a transient failover state; the caller re-resolves).
@spec topology() :: topology() | nil
The current routing topology, or nil in single-node / in-memory mode (no sharded control plane).