Message Flow
This page details how messages move through NSB at the protocol level โ the RabbitMQ queue sequences, the full operations table with channel assignment, and the status codes returned in each response.
Queue Naming Convention (RabbitMQ Backend)โ
nsb.{channel}.{client_id}
โโโ nsb.ctrl.{client_id} # Control channel
โโโ nsb.send.{client_id} # Outgoing payload channel
โโโ nsb.recv.{client_id} # Incoming payload channel
โโโ nsb.config.request # Daemon configuration request queue
โโโ nsb.config.response.{client_id} # Client-specific config response
RabbitMQ Message Flowโ
Client Initializationโ
1. Client creates NSBAppClient or NSBSimClient
2. Client sends INIT to nsb.config.request
3. Daemon responds to nsb.config.response.{client_id}
4. Client receives config and is ready
Message Sendingโ
1. App Client calls send(dest_id, payload)
2. Message published with routing_key = nsb.recv.{dest_id}
3. RabbitMQ routes directly to destination's RECV queue
4. No daemon mediation required
Message Fetching (Simulator)โ
1. SimClient calls fetch()
2. Consumes directly from nsb.recv.{simulator_id}
3. Calls post() to return processed message
In the RabbitMQ backend, once a client is registered, the broker handles all routing natively โ the daemon is only involved during the INIT handshake. Contrast this with the socket backend, where the daemon mediates every message. See Socket Backend vs RabbitMQ Backend for the full comparison.
Operations Tableโ
Every nsbm message carries a Manifest with an Operation, Originator, and OpCode. This table shows which channel each operation travels on and its direction:
| Operation | Originator | Channel | Direction | Description |
|---|---|---|---|---|
PING | Any client | ctrl | โ | Liveness check; daemon echoes SUCCESS or FAILURE |
INIT | Any client | ctrl | โ | Registration handshake; client sends IntroDetails; daemon responds with ConfigParams |
SEND | AppClient | send | โ Daemon | Submit payload to daemon TX buffer; no acknowledgement |
FETCH | SimClient | recv | โ | Poll for outbound payload; daemon responds with MESSAGE or NO_MESSAGE (PULL mode) |
POST | SimClient | send | โ Daemon | Deliver arrived payload to daemon RX buffer; no acknowledgement |
RECEIVE | AppClient | recv | โ | Poll for delivered payload; daemon responds with MESSAGE or NO_MESSAGE (PULL mode) |
FORWARD | Daemon | recv | Daemon โ | Proactively push payload to client (PUSH mode only) |
EXIT | Any client | ctrl | โ Daemon | Graceful shutdown signal; no response |
Notice that SEND and POST both travel on the send sub-channel (client โ daemon, no response expected), while FETCH and RECEIVE both travel on recv (bidirectional poll/response). This symmetry is intentional โ see Deep Architecture โ Multi-Channel Architecture for why.
Status Codes Tableโ
The OpCode field on a response tells the client how to interpret the message:
| Code | Used In | Meaning |
|---|---|---|
SUCCESS | PING, INIT, RECEIVE, FETCH | Operation succeeded |
FAILURE | PING, INIT | Operation failed |
MESSAGE | SEND, POST, FETCH, RECEIVE, FORWARD | Message carries a payload or key |
NO_MESSAGE | FETCH, RECEIVE | No payload found for requested node |
For the complete field-by-field schema (including CLIENT_REQUEST, DAEMON_RESPONSE, IMPLICIT_TARGET, and EXPLICIT_TARGET โ used for routing context rather than final status) see Protobuf Schema and Operations Reference.
Go Deeperโ
- Payload Lifecycle โ the exact step-by-step PULL and PUSH sequences these operations compose into
- Protocol โ Initialization Flow โ every message flow shown with full manifest/metadata fields
- RabbitMQ Backend โ complete Python and C++ usage for this transport