Skip to content
Ironflow is pre-1.0: APIs can change between releases. Pin a version. What is ready →

Emit Flow

Two ConnectRPC endpoints expose emit semantics:

  • PubSubService/Emit — fires an event, returns run IDs + event ID
  • IronflowService/Emit (alias for Trigger) — same semantics, different request/response messages

Both delegate to the same core logic in eventtrigger.Helper.Emit(). Neither publishes to the pubsub bridge directly — the events:{name} message is enqueued once through the transactional outbox (issue #487), which is the single source subscribers and projections read. One transaction writes the event row and its outbox entry, so a schema rejection (IRONFLOW_EVENT_SCHEMA_ENFORCEMENT=reject; the default is off) costs zero rows.

The call returns as soon as those rows are committed. Every matched function gets its own run, created waiting_for_capacity, and the caller gets the run IDs without waiting for any of them.

Functions are not the delivery mechanism. The outbox row is committed before trigger matching runs, so an event with no matching function is still stored and still published — emit() returns an empty run list, not an error. Subscribers and live projections receive the outbox publish either way. Workflow waitForEvent uses a separate path: DispatchMatched passes the event directly to the scheduler, which satisfies database correlations without waiting for the outbox or nats_seq.

Ironflow event fan-out

Dispatch does not fork on mode. Since ADR 0037 (#1206) every runnable run — push and pull — is admitted to the DB-backed dispatch_queue; there is no direct-dispatch bypass. The modes differ only after admission: a push run takes the synchronous fast-path and executes inline once its concurrency lane has room, while a pull run is never run inline and waits for a worker to claim it.

The event row is never deleted except by a retention policy or an explicit delete. It is inserted with processed=false, and MarkEventProcessed() flips it to true once its runs have been created and dispatched — the row stays in the database either way. IRONFLOW_EVENT_RETENTION_DAYS and IRONFLOW_ENTITY_EVENT_RETENTION_DAYS prune old rows when set, an entity-stream purge removes the events below its tombstone, and RedactEvent keeps the row but replaces its data with a placeholder. See ADR 0092.

That admission path, from ingress through the lease to completion, is drawn in full on the Request Lifecycle diagram. To wait on the runs instead of returning, see EmitSync Flow.