When people talk about matching engines, the first topic is usually performance.

That is understandable. Matching engines sit on a hot path. They consume orders, update books, produce trades, cancel orders, publish events, and feed every downstream surface that a trading venue depends on. Latency and throughput matter.

But in a large exchange-style system, the matching logic itself is often not the part that consumes the most engineering effort.

The hard part is keeping the engine's state stable, recoverable, and consistent while the system is running under load, restarting after failure, upgrading versions, publishing events, and feeding many downstream projections.

Performance is visible. Consistency is what keeps the system alive.

The business logic is only the center

The business logic of a matching engine is important, but it is only one part of the system.

At the center, the engine needs to decide:

  • whether an order can be accepted;
  • how it crosses existing liquidity;
  • which fills are produced;
  • which open quantity remains;
  • which balances, positions, or risk checks are affected;
  • which events should be emitted.

That logic is not trivial. But with a clear model, strong tests, and domain expertise, it can be made understandable.

The larger engineering burden appears around it.

message ingress
      |
      v
ordered command stream
      |
      v
matching / risk / account state
      |
      +--> durable history
      +--> snapshot
      +--> failover
      +--> event publish
      +--> downstream projections

Every arrow around the core introduces a consistency question.

Ingestion cannot miss or duplicate

The engine needs stable message ingestion.

Commands arrive from gateways, internal services, admin tools, recovery flows, and sometimes replay tools. Under normal load, ingestion looks straightforward. Under pressure, it becomes one of the most important parts of the system.

The command path must answer:

  • Was this command accepted exactly once?
  • If a client retries, is the result idempotent?
  • If a broker reconnects, where does consumption resume?
  • If the leader fails after accepting a command, who owns the final answer?
  • If a duplicate arrives later, can the system prove it is duplicate?

For a trading system, "probably processed" is not good enough.

Missing a command is dangerous. Processing it twice is dangerous. Reordering it can be dangerous. Losing the link between external sequence and internal transaction sequence makes incident response much harder.

The engine does not only need to be fast. It needs a command history that can be explained.

Restart must restore the same engine

A matching engine cannot restart into an approximate state.

After restart, the engine must know exactly which orders are open, which fills already happened, which events were published, which account or position changes were committed, and which command sequence is safe to continue from.

That requires more than saving a few database rows.

The engine needs a recovery model:

  • a durable committed history;
  • a snapshot that corresponds to a known point in that history;
  • a way to replay commands after the snapshot;
  • a way to verify that replay produces the same state;
  • a way to reject stale or duplicate external input after recovery.

If recovery reconstructs a state that is close but not identical, the system may still start. That is the dangerous case. It can look healthy while carrying a silent divergence.

For exchange infrastructure, restart is not an operational detail. Restart is part of the correctness model.

Snapshots are hard under load

Snapshots sound simple until the system is busy.

An idle engine can write a snapshot at any time. A hot engine is different. Commands keep arriving, events keep publishing, and downstream services keep reading derived views.

The snapshot has to represent a consistent point in the engine history.

That creates practical questions:

  • Can the engine take a snapshot without stopping the world for too long?
  • Which transaction sequence does the snapshot represent?
  • What happens if disk write fails halfway through?
  • Can the snapshot be verified before it becomes eligible for recovery?
  • Can the system continue from the snapshot plus the remaining log without gaps?

A bad snapshot is worse than no snapshot. It can make recovery faster, but wrong.

This is why snapshotting belongs to the same consistency design as command ordering, durable history, and replay. It should not be a background dump with unclear semantics.

Failover changes the problem

A single process can be deterministic and still not be highly available.

Once dynamic failover enters the design, the engine has to answer harder questions.

If the leader fails, the standby must know exactly which state it has, which command sequence is committed, which events are safe to publish, and whether it is allowed to become the new leader.

The system needs to avoid split-brain behavior. It also needs to avoid a standby taking over from a state that is almost current but missing a committed command.

Failover is not only about health checks and process supervision. It is about proving that the new leader has the right state boundary.

For a serious matching engine, "fast failover" is not enough. The failover must be correct.

Events are part of the consistency contract

The matching engine does not end at the matching engine.

Every committed state change feeds downstream systems:

  • market data projections such as kline and order book views;
  • database persisters;
  • user position, account, and order query services;
  • risk services;
  • WebSocket services;
  • reconciliation and audit tools;
  • monitoring and operation dashboards.

These consumers all depend on a consistent source.

If an event is published before the engine state is durable, downstream systems can observe a future that recovery may later reject. If an event is published twice, consumers need idempotency. If an event is missing, projections become incomplete. If event order is inconsistent with engine order, market data, account state, and risk views can disagree.

The real requirement is not merely "publish events."

The requirement is to publish events from the same committed history that defines engine state.

Projections must agree on the same world

Downstream projections are useful because each one serves a different access pattern.

Market data wants order book and kline views. A database persister wants durable query tables. A user service wants positions, accounts, and open orders. A risk service wants current exposure. A WebSocket service wants low-latency updates.

These systems do not need to store data in the same format. But they do need to derive from the same ordered truth.

Without that, operators face the hardest class of production incident:

the matching engine says one thing
the order query says another thing
the account service says a third thing
market data already published something else

At that point, the question is no longer "is the engine fast?"

The question is "which view is true?"

StateVec starts from the position that the committed transaction path should answer that question.

Version upgrades are consistency events

Version upgrades are often treated as deployment mechanics.

For a matching engine, they are part of the state model.

If the engine upgrades while state is live, the new version must understand existing records, existing snapshots, existing logs, existing events, and existing downstream consumers. If the command handler changes, replay needs a clear rule for which logic version is used for which command range.

Even a small schema change can be risky if the engine cannot explain:

  • how old state becomes new state;
  • whether old commands still replay;
  • whether old events remain compatible;
  • which projection version downstream services should read;
  • how rollback works if the upgrade fails.

The bigger the system, the less realistic it is to rely on manual repair after an upgrade.

The engine needs an upgrade model that respects deterministic history.

Determinism is the way out

The direction is a deterministic state machine.

The engine receives ordered commands. It executes deterministic business logic. It produces a committed result that includes state changes and events. It writes that result into durable history. State, event publication, replay, audit, recovery, and verification are all tied back to the same ordered transaction path.

command
  -> deterministic execution
  -> TxResult
  -> durable history
  -> state delta
  -> events
  -> projections

That model does not remove operational complexity. It gives the complexity a place to live.

Instead of asking every projection, repair script, consumer, and database table to independently define truth, the system can point to one committed history.

The real goal is replicated determinism

A deterministic state machine is already useful in one process.

The larger goal is a replicated deterministic state machine.

That is the hard version. It means multiple nodes can follow the same ordered history, rebuild the same state, verify the same results, and support failover without inventing a new truth during recovery.

For exchange-grade systems, this is close to the holy grail:

  • no lost commands;
  • no duplicate business transitions;
  • replayable state;
  • consistent snapshots;
  • deterministic failover;
  • event publication from committed truth;
  • downstream projections built from one ordered source.

This is why StateVec is not only trying to make business logic faster.

The real target is stable, explainable, recoverable consistency for systems where state correctness is the product.