Simulation & Durable Objects Proof
Running the Proof: Watch the Race Condition Happen
Section titled “Running the Proof: Watch the Race Condition Happen”The simulator runs two experiments in real time. You trigger them. You watch the numbers diverge. This isn’t a chart or a report—it’s live evidence.
Experiment 1: The Safe Path (Durable Objects)
Section titled “Experiment 1: The Safe Path (Durable Objects)”Trigger 125 concurrent allocation requests against the safe path. Watch the counter climb. It stops at 100. Every. Single. Time.
- 100 units allocated.
- 25 requests rejected with 409 Conflict.
- Zero oversell.
- Latency: 12–20ms p50, <50ms p99.
- Why it works: All 125 requests route to a single Durable Object per SKU. The object is single-threaded. It processes them in order. Request 101 arrives and sees 100 already allocated—rejection.
Experiment 2: The Eventual Path (Intentional Race)
Section titled “Experiment 2: The Eventual Path (Intentional Race)”Now run the same 125 requests against the eventual path (SQL/D1 with the anti-pattern: SELECT → check → UPDATE).
Watch it over-allocate. By 20–25 units. Every. Single. Time.
- 125 units allocated successfully.
- 0 requests rejected.
- 100% oversell.
- Why it fails: Requests 1–100 all check the database and see “100 available.” None of them have written their increment yet. By the time writing catches up, all 125 have passed the check. The system can’t enforce the hard limit.
This is the moment most stakeholders “get it.” You’re not arguing theory. They’re watching it happen live.
What You See in the UI
Section titled “What You See in the UI”Before the Run
Section titled “Before the Run”A simple control panel shows two buttons:
- “Run Safe Mode (125 concurrent)”
- “Run Eventual Mode (125 concurrent)”
Below that, two counters live-update:
- Allocated Units (climbs as requests succeed)
- Failed Units (climbs as requests cap out or race)
A third band shows the overbooking delta: the gap between what was allocated and what should have been. In safe mode, this stays at 0. In eventual mode, it ticks up to +20, +21, +25.
Click Safe Mode
Section titled “Click Safe Mode”The UI fires 125 concurrent allocations at the safe path. You watch:
- Counter climbs: 1, 2, 3… 50… 100
- Stops at 100. No matter how many are still pending. The UI shows “25 requests pending rejection.”
- Takes ~2–3 seconds for all to complete.
- Overbooking delta: 0
Click Reset
Section titled “Click Reset”Counters go to zero. Ready for the next run.
Click Eventual Mode
Section titled “Click Eventual Mode”Same thing, but different outcome:
- Counter climbs: 1, 2, 3… 50… 100… 110… 125
- All 125 requests pass (at least initially).
- Overbooking delta: +25
The stark visual difference between “stops at 100” and “reaches 125” is the whole proof in one glance.
Live WebSocket Feed (Side Panel)
Section titled “Live WebSocket Feed (Side Panel)”As numbers update, a “Details” panel shows per-SKU allocation events in real time:
sku-001: +1 allocated (safe mode) - latency 18mssku-002: +1 allocated (eventual mode) - latency 92ms- etc.
If the guardrail trips (e.g., virtual budget exceeded), a banner appears: “Guardrail triggered. No further allocations. Reset to continue.”
[!TIP] When presenting: “Safe mode caps at 100—no oversell. Eventual mode reaches 125—you see the race condition. Guardrail catches it before billing exposure.” This three-moment arc proves both the problem and the solution.
Guardrail Flow
Section titled “Guardrail Flow”graph TD
Start(["Allocation Request"]) --> CheckGuard{"Guardrail tripped?"}
CheckGuard -- Yes --> Block["403 + WS close"]
CheckGuard -- No --> Mode{"mode=safe?"}
Mode -- Safe --> DOAlloc["Durable Object allocate"]
Mode -- Eventual --> D1Alloc["D1 allocate (race window)"]
DOAlloc --> Telemetry["Emit metrics"]
D1Alloc --> Telemetry
Telemetry --> EvalGuard{"Budget/units exceeded?"}
EvalGuard -- Yes --> Trip["Set guardrail flag in KV"]
Trip --> Block
EvalGuard -- No --> Continue["Respond"]
Evidence Capture
Section titled “Evidence Capture”- Metrics: success/fail counts, overbooking delta, p50/p99 latency.
- Telemetry: Analytics Engine events for allocations, guardrail triggers, hibernation resumes.
- Logs:
wrangler tail --filter allocateand guardrail filters.
Anti-Patterns Demonstrated
Section titled “Anti-Patterns Demonstrated”- Read–modify–write races in SQL without serialisation.
- Over-allocation under burst despite “row counter” checks.
- Latency penalty of regional DB compared to edge-serialised DO.