fix(producer): wait on idle instead of Sleep in StopSafely - #755
Conversation
StopSafely polled the queue with Thread.Sleep(10) while the background loop already tracked idle via _draining / IsIdle. Disconnect and Dispose sat on that 10 ms tick whenever anything was still queued behind an in-flight write. Wait on a waitable idle event (queue empty and no write in flight) with the same timeout, then stop the parked loop. Timeout still force-stops. Co-authored-by: Tyler Kron <tylerkron@gmail.com>
|
/agentic_review |
Code Review by Qodo
1.
|
The loop signalled idle as check-empty, Set, re-check, Reset. A Send landing between the check and the Set left the event briefly set with a message queued, and a StopSafely waiting on it could wake in that window, stop the loop and leave the message unwritten - exactly the 'send stop-streaming, then disconnect' teardown apps do. The check+Set and Send's Reset+Enqueue now share one short lock, so idle is only ever signalled with the queue empty. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
/agentic_review |
|
Code review by qodo was updated up to the latest commit 1be2ec7 |
|
Reviewed (Claude): approve after fixing a real race where a Send right before Disconnect could be dropped (Send's reset+enqueue and the idle signal now share a lock). Qodo-clean on 1be2ec7, CI green — ready for review. |
PR Summary by QodoWait for producer idle state during safe shutdown
AI Description
Diagram
High-Level Assessment
Files changed (2)
|
|
Code review by qodo was updated up to the latest commit 1be2ec7 |
What was wrong
MessageProducer.StopSafely()(called byDisconnect()andDispose()) waited for pending commands by checking the queue every 10 ms. Two consequences:StopSafelyreported success even though the command never went out.How it was fixed
The producer's background thread now signals an event when it goes idle — nothing queued and no write in progress.
StopSafelywaits on that event with the caller's timeout, so it returns the moment the last write completes. If a write is still stuck when the timeout expires, it returnsfalseand force-stops, as it already did for a full queue.Normal disconnects behave the same, just without the polling delay. The only visible difference is the stuck-write case:
StopSafelynow returnsfalseinstead oftrue. No production caller in Core reads that return value.Tests
StopSafelywaits for both, then returnstrue.StopSafelytimes out and returnsfalse.Pairs with #739, which removes the test-side sleeps. Both touch
MessageProducerTests.csin different places and merge cleanly in either order.Verification
OperationSerializertests 20× under 4-core CPU load: 0 failures.🤖 Generated with Claude Code