Service Runtime
Shared-memory service integration and local broker communication.
The service runtime is the application-facing side of RingLoom. A service imports ringloom_service, starts a RingLoomEngine, registers message handlers, creates clients for target service names, and sends messages without needing to know whether the selected target is local or remote.
Main API surface
| Type | Purpose |
|---|---|
RingLoomEngine |
Starts and owns the service runtime: metadata, registration, control agent, message consumer, clients, counters, and shutdown. |
ServiceConfig |
Runtime configuration for storage path, group, service name, broker node ID, buffer sizes, leader election, blocking mode, and idle strategy. |
ServiceClient |
Client proxy for a discovered target service name. Handles local producers, remote broker routing, load balancing, leader sends, and zero-copy claims. |
MessageConsumer |
Reads inbound application messages from the service message ring and dispatches to the registered handler. |
ControlAgent |
Processes service control messages such as registration responses, service-instance snapshots, and leader changes. |
IpcProducer / IpcConsumer |
Low-level shared-memory producer/consumer wrappers over RingLoom’s MPSC ring buffer. |
Service startup
RingLoomEngine.start performs the service-side bootstrap:
- opens the local broker metadata file;
- allocates a unique service ID from the broker metadata;
- creates this service’s metadata file;
- writes a
RegisterServicemessage to the broker control ring; - waits for
RegistrationResponseon the service control ring; - writes an initial heartbeat;
- initializes the service client registry;
- starts the message consumer thread;
- starts the control agent thread.
The service metadata file is created under:
<storage_path>/<group>/services/<service_name>_node<node_id>_<service_id>.dat
Shared-memory channels
A running service participates in four shared-memory channels:
| Channel | Backing file | Direction | Purpose |
|---|---|---|---|
| Broker control ring | broker metadata | service → broker | Register, subscribe, unregister, and related control messages. |
| Service control ring | service metadata | broker → service | Registration response, discovery snapshots, and leader updates. |
| Broker send ring | broker metadata | service → broker | Outbound application messages whose target is on a remote node. |
| Service message ring | service metadata | producers → service | Inbound application messages from local producers or the local broker receiver. |
The application handler only sees delivered application messages. Control-plane messages are consumed by the service runtime.
Same-host direct path
When a ServiceClient target is on the same node, the client writes directly into the target service’s message ring. The broker is not involved in the data path.
service A ServiceClient -> target service message ring -> target MessageConsumer
The fastest version of this path is the claim/commit API. The caller claims writable bytes in the target ring, writes the payload directly into mapped memory, and commits. No intermediate payload allocation or copy is required by RingLoom.
Cross-host routed path
When a target service instance is on another node, the same ServiceClient writes to the local broker send ring with remote routing identifiers in the message header:
service -> local broker send ring -> broker sender loop -> TCP -> remote broker receiver loop -> target service ring
The application uses the same service-name client abstraction. Discovery tells the client which node and service ID each target instance currently has.
Service discovery
RingLoomEngine.createClient("pricing") returns a ServiceClient and sends a subscription request to the broker. Whenever matching instances appear, disappear, or change leader status, the broker sends a complete ServiceInstances snapshot.
The client maintains a target list containing:
- target node ID;
- target service ID;
- leader flag;
- local producer if the target is same-host;
- broker-routed producer metadata if the target is remote.
The default selection strategy is round robin across available instances. Callers can also send to an explicit (target_node_id, target_service_id) or to the current leader.
Message receiving
The service message consumer reads records from the service message ring. Each delivered message contains transport metadata such as source node, source service, target node, target service, template ID, flags, correlation ID, and payload bytes.
A Zig service registers a handler with:
engine.setMessageHandler(&messageHandler);
Handlers should stay allocation-free on the hot path: decode fixed layouts, update preallocated state, send using a reused client or claim, and avoid per-message logging.
Send APIs
ServiceClient supports several send styles:
| API style | Use case |
|---|---|
send / sendMessage |
Copy-based convenience send to a load-balanced instance. |
sendTo / sendToMessage |
Send to a specific target node and service ID. |
sendToLeader / sendToLeaderMessage |
Send to the discovered leader instance. |
tryClaim |
Claim payload memory for zero-copy load-balanced sends. |
tryClaimTo |
Claim payload memory for a specific target. |
tryClaimToLeader |
Claim payload memory for the current leader. |
Request variants accept an explicit correlation ID so applications can link replies, timeouts, or tracing records.
Back-pressure contract
The service runtime reports expected runtime outcomes as typed send errors or status codes in bindings. Common outcomes include:
- no available instance;
- no leader available;
- target ring full;
- broker send ring full;
- flow-control back-pressure;
- peer congestion;
- peer disconnected.
Applications should count and handle these outcomes according to their domain policy. They are not treated as crashes by the runtime.
Service-side observability
Service metadata includes counters, heartbeat timestamps, ring positions, and error state. Native services can register custom counters and gauges through the C ABI, and external tools can inspect service metadata through ringloom-stat or the Prometheus exporter.