Expand description
Downstream consumer that records completed fills into the competition tables.
This is the ingestion side of competitions, decoupled from the websocket
broadcast path. The recorder consumes a stream of [EngineMessage] and, for
each OrderFilled, persists a competition fill.
§Source-agnostic by design
run takes a plain mpsc::UnboundedReceiver<EngineMessage>, so it does not
care where the fill stream comes from. Today the runtime feeds it from the
in-process engine EventBus (TOPIC_FILLS subscription). When the engine runs
out-of-process (see the transport-evolution roadmap), the same recorder is fed
by a NATS JetStream consumer instead, with no change here. Other downstream
services (analytics, auditors) subscribe to the same stream the same way.
§Failure handling
A competition write failure is logged and metered but does NOT crash the
engine node. The previous implementation recorded fills inline in the
websocket forwarder and triggered a full process shutdown on failure, so a
transient leaderboard DB error could take down trading. Fill recording is
idempotent (record_competition_fill is ON CONFLICT (trade_id, wallet) DO NOTHING), so a dropped fill is safely re-recordable.
§Durability caveat (not yet a durable follower)
This consumes an in-memory event stream. Fills already written to
competition_fill_events survive restart, but a fill emitted but not yet
recorded when the node dies is NOT recovered: engine replay rebuilds engine
state without re-emitting fills to the event bus. Closing that crash window
requires making competition a durable external-follower projection that
replays the fill stream from the journal/NATS at a recorded offset (tracked
separately).
Structs§
- Competition
Fill Recorder - Consumes the engine fill stream and records competition fills.
Traits§
- Competition
Fill Sink - Minimal sink the recorder depends on: persist one competition fill.