The repository includes two kinds of examples:

  • small test services used by the end-to-end and performance harnesses;
  • the order-management sample, which is a complete two-node application.

Use the small services when you want to validate one behavior quickly. Use the order-management sample when you want to see how multiple services fit together.

Echo and ping: simplest local IPC

The quickstart uses ringloom-test-echo-service and ringloom-test-ping-service with one broker. The flow is:

ping service -> echo service

Because both services register on the same broker node, the ping client’s discovered target is local. Sends go directly into the echo service’s message ring through shared memory.

Useful options:

Service Option Purpose
echo --max-messages N Stop after receiving N messages.
echo --reply-delay-ms N Simulate a slow handler.
ping --message-count N Number of messages to send.
ping --message-size N Payload size in bytes.
ping --send-interval-ns N Pace sends for unloaded latency measurement.
ping --spin-timeout-ms N Retry briefly when back-pressure occurs.
both --storage-path, --group, --broker-node-id Match the local broker config.

Forwarder chain

ringloom-test-forwarder-service is used by the harness to validate multi-hop service routing. The pattern is:

producer -> forwarder -> echo

This demonstrates that a service can receive a message through its message handler and then use a ServiceClient to send the next message. Keep forwarding handlers small: decode fixed fields, update counters, claim the outbound buffer, write the next payload, and commit.

Slow consumer and back-pressure

ringloom-test-slow-consumer-service and echo’s --reply-delay-ms option are useful for seeing how the system behaves when a target service cannot drain its message ring as fast as producers fill it.

Expected behavior under pressure:

  • producers may see SendBufferFull or flow-control errors;
  • ring usage reported by ringloom-stat rises;
  • peer send pending counters rise for remote targets when enabled;
  • the system remains stable instead of allocating unbounded queues.

Back-pressure is not an exceptional condition. Production services should count it, decide whether to retry, shed, buffer outside the hot path, or report overload to upstream callers.

Leader-aware services

ringloom-test-leader-service exercises per-service leader election. Multiple instances register with the same service name and leader election enabled. The broker designates one leader and sends leader-change updates to subscribers.

A caller that needs active-instance semantics should use leader-aware send paths rather than implementing its own coordination:

  • send to any instance for load-balanced work;
  • send to the leader for ordered or stateful work;
  • subscribe to lifecycle updates if you need logs or cold-path reconfiguration when the leader changes.

Crash and restart scenarios

ringloom-test-crashy-service exists for recovery tests. It helps validate that broker heartbeat checks remove dead services, notify discovery subscribers, and allow replacement services to register cleanly.

For local debugging, inspect the preserved e2e temp directory after a failing test. The harness keeps generated config, process logs, result JSON, and storage metadata under /tmp/ringloom-e2e-<scenario>-<seq>/ when a scenario fails.

Order-management sample

The sample under samples/order-management starts a two-node application with six service types:

order-simulator -> order-gateway -> risk-service -> matching-engine -> execution-service -> portfolio-service

Default placement:

Node Services
node 1 order-simulator, order-gateway, risk-service, portfolio-service
node 2 matching-engine, execution-service

The normal message path intentionally crosses broker nodes twice:

  1. simulator to gateway — local shared-memory IPC;
  2. gateway to risk — local shared-memory IPC;
  3. risk to matching — cross-broker TCP route;
  4. matching to execution — local shared-memory IPC on node 2;
  5. execution to portfolio — cross-broker TCP route back to node 1.

Run the default profile:

zig build sample-order-management
zig build run-sample-order-management -- --profile default

Run the full profile:

zig build run-sample-order-management -- --profile full --orders 100000 --rate-per-sec 50000

The full profile adds another risk-service instance and another matching-engine instance. It demonstrates load balancing, leader election for matching, lifecycle updates, and optional process restart behavior.

What the sample demonstrates

Feature Where to look
Fixed wire payloads samples/order-management/src/common/protocol.zig
Shared service names samples/order-management/src/common/service_names.zig
Service startup wiring samples/order-management/src/common/app.zig
Deterministic order generation order_simulator.zig
Local forwarding order_gateway.zig and risk_service.zig
Cross-node routing risk_service.zig to matching_engine.zig, then execution_service.zig to portfolio_service.zig
Leader-aware routing matching_engine.zig in the full profile
Results and summaries workspace results/ directory printed by the run script
Runtime inspection ringloom-stat command printed by the run script

Application payload pattern

The sample uses a small domain envelope followed by fixed extern struct bodies. The envelope carries correlation and timing fields. The RingLoom transport already carries routing and template metadata, so the application payload should not duplicate that information unless the domain needs it.

A typical hot-path send looks like this conceptually:

  1. choose a target client by service name;
  2. claim outbound payload memory with a template ID and payload length;
  3. write the fixed payload directly into the claim buffer;
  4. commit the claim;
  5. increment application counters outside the critical path when possible.

Avoid per-message heap allocation, string formatting, JSON serialization, or log output in handlers. Those are fine for startup, shutdown, and summary paths, but they defeat the predictable latency model if they run for every message.

Testing scenarios in the repository

The e2e harness covers the patterns that the examples build on:

Scenario family Coverage
startup broker config, metadata creation, signal handling
registration single and multiple services, service ID assignment
local IPC direct same-host service-to-service communication
discovery late registration and removal updates
cross-broker two- and three-broker routing
fragmentation large message handling
heartbeat timeout dead service cleanup
restart metadata reuse and cleanup
leader election failover and multiple instances
graceful unregister clean shutdown and discovery removal
backpressure slow consumers and multiple producers

Run them with:

zig build e2e

Use these scenarios as executable examples when you are designing a new service topology.