Concurrency
The contention model is a single writer serialized per Bucket, event-sourced. The queue is what “takes the beating”; the event log is, at once, the FSM audit and the recovery mechanism.
Partition = Bucket
Section titled “Partition = Bucket”A single writer per Bucket (sector × Unit type).
- QUANTITATIVE: the Bucket’s capacity is a single-owner counter → serialized decrement, no oversell, no lock.
- QUALITATIVE: locks on the Units inside the Bucket, naturally serialized by the writer.
- A derby’s beating spreads across dozens of Buckets (one queue per Bucket) instead of hammering a single writer.
Cluster is domain, not a protocol primitive
Section titled “Cluster is domain, not a protocol primitive”Two cases that look like a cluster:
- A whole camarote table = domain granularity: the table is the Unit (a
tables/restaurantcatalog materializes “Table 5” as one Unit; the N seats are an attribute/capacity). Reserving = aHoldof 1 Unit. Zero cluster machinery. - Co-reservation of distinct Units (a wheelchair space + companion, possibly in
different Buckets): declaration in the Catalog (a
cluster_id, exposed in theListUnitsmetadata) + a Reservations policy (“a Hold with a clustered Unit requires its mates → elsePOLICY_VIOLATION”) + the existing ATOMIC for all-or-nothing.
Hot state + event-sourcing
Section titled “Hot state + event-sourcing”The writer keeps the Bucket’s state hot in memory and applies commands 1-to-1. Each
effect is an append-only event persisted to Postgres → enabling replay to rebuild
the Bucket state on recovery/failover. The event log unifies what the park kept separate:
the FSM, the audit (fsmevent), and the recovery WAL.
Atomicity (multi-item)
Section titled “Atomicity (multi-item)”- Intra-Bucket (a family buying 4 seats together) → atomic for free: one command, one writer, all-or-nothing.
- Cross-Bucket (seats in different sectors, or ticket + parking) → a 2-phase reservation between the writers involved (reserve → commit; if any refuses, roll the holds back). Coordinated by the service, not the Channel.
Idempotency & TTL
Section titled “Idempotency & TTL”- Every command carries an idempotency-key (from the Channel). A replay returns the
prior result (
IDEMPOTENT_REPLAY) — killing oversell-by-reissue and batch cleanup jobs. Holdcarries a TTL; the writer arms the timer and auto-Releases on expiry.Extendextends it.Fulfillis idempotent (booking token).