vike
Concepts

The event bus

A defer-and-deliver FIFO whose delivery order is load-bearing, whose handler reports whether it actually folded an event, and whose drain guard salvages the event a panic was holding.

Every venue event the execution core folds passes through one queue: crates/vike-exec/src/bus.rs's EventBus. It is small, and its header states the one property that makes it more than a VecDeque: defer-and-deliver. A publish appends to the back of the FIFO; if a drain is already running the call returns and the event waits its turn; otherwise the call drains, delivering each event in full before the next one starts. The ordering is load-bearing rather than tidy — the example the header gives is a one-cancels-other bracket, where the auto-cancel publishes OrderCanceled while OrderFilled is being delivered, and the cancel must land after every subscriber has seen the fill.

One writer, one outbox

The single-writer core owns both the bus and its handler, so callback re-entrancy is impossible by construction. Instead of publishing back into the bus mid-fold, a handler pushes follow-on events into an Outbox, and the drain loop appends that outbox to the back of the same FIFO after the fold returns. Follow-ons are therefore delivered after every already-queued event and never recursively — byte-identical delivery order to the original semantics, and clean under the borrow checker. The draining latch is kept as an explicit field even though the single-writer core can never set it re-entrantly; the parity test's chained publisher exercises it, and the semantics stay written down.

EventHandler is the bus's one subscriber type, and ExecutionEngine is the handler: its on_event folds the venue stream through the order state machine and the account, and — as crates/vike-exec/src/execution_engine/mod.rs's header says — it folds state only; durable persistence belongs to the runtime's journal. Every delivered event is also appended to the bus's delivered log, which the runtime takes each batch and folds into its bounded recent-events ring — the seam the desktop app's event echo reads through a lossy observer channel, and the seam the fixtures assert delivery order against.

The fold reports a verdict

on_event returns a Fold: Applied when the event actually changed state, Dropped when the handler refused it — an unknown client-order-id, an illegal transition in the order lifecycle, a reconnect replay, an event for a symbol or venue this engine does not own, or a non-finite venue number. "Invalid transitions are dropped" is a core law of the order management system, and the Fold doc records why the verdict had to become visible: before it existed on_event returned nothing, so a downstream reaction keyed off the event rather than off the fold's acceptance of it, and fired for events the engine had refused. The live one-triggers-other / one-cancels-other drive was exactly that — a fabricated OrderFilled on an unknown client-order-id cancelled its sibling and armed its held children even though the engine had dropped the event and counted it into dropped_unknown_coid.

publish returns the verdict for the event it was handed. Follow-on events drained by the same call carry their own verdicts, which are not reported: no caller reacts to them, and the site that published them is the one that would. crates/vike-core/src/runtime/mod.rs's dispatch names the consumer this exists for — the contingency drive on the venue ingest lane is gated on the fold's verdict, because without that gate a fabricated fill on one bracket leg cancels its sibling and leaves a position naked. The in-process client seam is deliberately not gated.

The deferred branch answers Applied, and it is not for you

When publish finds a drain already running it returns Fold::Applied without knowing anything. That branch is structurally unreachable in the single-writer core — draining can only be set by a publish higher in the same call stack, and the engine publishes into its outbox rather than back into the bus — so it exists only for the parity test's chained publisher, and answering Applied there keeps that path byte-identical to its pre-verdict behaviour; answering Dropped would invent a new way to orphan a legitimate bracket on a path nobody exercises. A caller that genuinely needs the verdict of a deferred event must not use this seam.

What a panic mid-fold does

The drain is unwind-safe in the way a try/finally would be: a drop guard clears the draining latch on the way out, so after the runtime's catch_unwind the next publish drains normally, with every undelivered event still queued in order. The publish doc records the review finding that put it there — without the guard, one in-drain panic would silently defer every later event forever.

The same guard does a second job. The event being folded is held in an in_flight slot during on_event; a clean return moves it into delivered, so anything still in the slot when the guard drops was lost to a panic, and the guard pushes it into a poisoned list instead of letting it go. The runtime drains take_poisoned after its catch_unwind fires and surfaces each as a lost terminal in the recent-events ring, so a panic can never silently strand an order — the test panic_mid_fold_salvages_the_in_flight_event pins that the salvaged event is recorded exactly once and is not re-folded. This is the bus's half of the core's panic policy; the runtime's half is on the execution core page.

Where the events come from

The bus consumes what the ingest lanes deliver — the lossless EventSender every venue adapter holds pushes canonical events into the core's single ingest channel, and the drain loop publishes each one here. The variants themselves, who emits each and what the state machine does with it, are one page each under events.

On this page