{"record":{"id":"12722ab0fb19d4c7","repo":"nautechsystems/nautilus_trader","slug":"second-submit-fills-the-slot","errorCode":null,"errorMessage":"second submit fills the slot","messagePattern":"second submit fills the slot","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/event_store/src/writer/mod.rs","lineNumber":1410,"sourceCode":"            EventStoreWriter::spawn(Box::new(backend), clock, halt, config).expect(\"spawn\"),\n        );\n\n        writer.submit(entry_draft(10)).expect(\"first submit fits\");\n\n        let mut waited = Duration::ZERO;\n        while appends_seen.load(Ordering::SeqCst) == 0 && waited < Duration::from_secs(2) {\n            std::thread::sleep(Duration::from_millis(5));\n            waited += Duration::from_millis(5);\n        }\n        assert_eq!(\n            appends_seen.load(Ordering::SeqCst),\n            1,\n            \"writer thread did not reach the gated append\",\n        );\n\n        writer\n            .submit(entry_draft(11))\n            .expect(\"second submit fills the slot\");\n\n        // This submit stalls past the threshold and latches the halt\n        let stalled = writer.submit(entry_draft(12)).expect_err(\"must stall\");\n        assert!(\n            matches!(stalled, SubmitError::HaltSignaled { .. }),\n            \"was {stalled:?}\",\n        );\n\n        // A second submitter now waits in the retry loop while the channel stays full\n        let writer_for_thread = Arc::clone(&writer);\n        let retrying = std::thread::spawn(move || writer_for_thread.submit(entry_draft(13)));\n        std::thread::sleep(Duration::from_millis(20));\n\n        // Release the gate: the freed slot must not rescue the retrying submit\n        let (lock, cvar) = &*gate;\n        *lock.lock() = true;\n        cvar.notify_all();\n","sourceCodeStart":1392,"sourceCodeEnd":1428,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/event_store/src/writer/mod.rs#L1392-L1428","documentation":"Test panic from `.expect(\"second submit fills the slot\")` at crates/event_store/src/writer/mod.rs:1410. After the writer thread is confirmed blocked at the gated append (appends_seen == 1), the second submit must enqueue into the now-free capacity-1 slot and return `Ok`; the expect panics if it is rejected. A rejection means the slot was still occupied, a halt already latched, or the retry loop timed out past the threshold.","triggerScenarios":"Calling `submit` when the capacity-1 channel is not actually drained (writer thread never dequeued the first entry), or when the 50ms `halt_threshold` expired during polling so `HaltSignaled`/`Closed` is returned.","commonSituations":"Slow CI where the 5ms polling loop takes too long and the halt fires early; tests asserting on `appends_seen` without confirming the gate is held; fixture configs with too-small `halt_threshold` relative to polling overhead.","solutions":["Increase `halt_threshold` so the second submit's brief retry window cannot trip the stall latch.","Confirm the writer thread really consumed the first entry (the `appends_seen == 1` assert) before the second submit; keep that poll bounded and generous.","Match on `SubmitError` to log whether the failure is `HaltSignaled` (threshold too tight) or `Closed` (thread halted) instead of a bare expect.","Ensure the gate starts closed (`Mutex::new(false)`) so the writer stays blocked and the slot semantics hold as the test assumes."],"exampleFix":"// before\nwriter\n    .submit(entry_draft(11))\n    .expect(\"second submit fills the slot\");\n// after\nwriter\n    .submit(entry_draft(11))\n    .expect(\"second submit must fill the drained capacity-1 slot before any halt\");","handlingStrategy":"validation","validationCode":"// Confirm the writer thread reached the gated append before filling the slot\nassert_eq!(appends_seen.load(Ordering::SeqCst), 1,\n    \"writer thread did not reach the gated append\");","typeGuard":"match writer.submit(entry_draft(11)) {\n    Ok(_) => {},\n    Err(SubmitError::HaltSignaled { .. }) => eprintln!(\"halt_threshold expired before submit\"),\n    Err(SubmitError::Closed) => eprintln!(\"writer halted\"),\n}","tryCatchPattern":"writer.submit(entry_draft(11))\n    .unwrap_or_else(|e| panic!(\"second submit rejected: {e:?}\"));","preventionTips":["Wait for appends_seen == 1 before the second submit to guarantee the slot drained.","Keep polling loops bounded but tolerant (multi-second ceilings) on slow CI.","Raise halt_threshold above total polling overhead.","Assert gate state explicitly before slot-filling submits."],"tags":["rust","panic","backpressure","timing"],"backgroundTag":"internal-invariant-violation","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}