ADR-014: Sequenced Input Disruptor Replaces Matcher Poll and Lock
Statusβ
Proposed
Dateβ
2026-06-09
Contextβ
State 009's OrderMatcherService evaluates open orders on a @Scheduled tick (default 1000 ms),
guards all order mutation with a ReentrantLock, receives price ticks out-of-band via a NATS
subscription into a ConcurrentHashMap, and queries JPA per tick. This adds up to a full polling
interval of latency, lock contention and context switches, racy interleaving between price updates and
matching (mediated only by the lock), and continuous hot-path allocation.
The LMAX architecture (Fowler) removes all of these with one mechanism: every state-mutating input is funneled through a single pre-allocated ring buffer, stamped with a strictly monotonic global sequence number, journaled and replicated in parallel, and consumed by a single-threaded processor gated behind a sequence barrier.
Decisionβ
- All state-mutating inputs; order create/cancel/force-fill, price ticks, and market trades; enter one input disruptor ring via the Gateway and receive a global sequence number (FR-09B01, FR-09B06, FR-09B08).
- The
@Scheduledpolling tick andorder.matcher.tick-msare removed; matching is event-driven (FR-09B02). orderMutationLockis removed; the BLP is the sole writer of matcher state (NFR-09B04).- Three parallel input handlers (journaler, replicator, un-marshaller) run ahead of the BLP, which is
gated at
min(J, R, U)so every event it processes is already durable, replicated, and decoded (FR-09B03, FR-09B04). - Ring capacity is power-of-two and sized per the burst math in
data-model.md; ring-full applies bounded producer backpressure with a remaining-capacity gauge (FR-09B07). - Wait strategy is profile-selected:
BlockingWaitStrategyindemo/CI,BusySpinWaitStrategyon BLP/journaler inperf.
Consequencesβ
- Matching latency drops from up-to-a-tick to event-arrival; prices and orders are one totally-ordered stream, eliminating the price/match race by construction.
- Durability precedes processing: an acknowledged order is journaled and replicated before the BLP acts, enabling deterministic replay and warm failover (ADR-016 relies on this).
- The ring is the only contention point and is lock-free by construction; under overload the system degrades via bounded backpressure instead of unbounded queue growth.
- Cost: a new moving part (ring + handlers + sequence barrier), a busy-spun core in the perf profile, and ring-sizing as an explicit operational concern.