- Diagrams
- Flows
- Event Ingest Flow
Event Ingest Flow
External systems can publish events directly to NATS, bypassing the HTTP API. The EventRouter durable consumer picks them up and routes them through the same dispatch pipeline as emit() — once the event row is written, an ingested event is indistinguishable from an emitted one. The row commits with the same events:{name} outbox entry, so PUBSUB carries one message with the raw data, and a rejected PUBSUB publish is retried rather than lost.
An envelope that omits data uses JSON null for schema validation, persistence and delivery, just like an explicit "data": null.
The consumer is named and durable (event-router), filters ironflow.*.*.events.ingest.>, and uses explicit acks with a 30-second ack wait and no JetStream delivery limit (MaxDeliver: -1). The router counts processing failures durably and retains a delivery in Dead Letters after five. Permanent errors skip that budget: an unmarshal failure, a rejected event name (#1733), and a schema validation failure (#1951, only when IRONFLOW_EVENT_SCHEMA_ENFORCEMENT=reject) all describe bytes that will never become valid. msg.Nak() negatively acknowledges transient errors and triggers immediate redelivery, ignoring AckWait. The 30-second wait applies when no acknowledgement arrives. A frozen instance, a full receipt quota and unavailable broker proof are retried with a growing delay and never spend the budget.
Reaching this path needs publish rights on the internal ironflow.> subject space, and no in-tree producer writes to events.ingest.> — it is an operator door, not an anonymous one. The event name still arrives unmarshaled straight off the wire, so it is bounds-checked here rather than relying on the deployment property.