channel: drop queued messages when the Receiver drops
A queued Envelope::Call was stranded until the last Sender dropped, so a caller parked in gen_server::call was never released with ServerDown when a *named* server was request_stop'd — the registry's inbox Sender clone (lazy prune) kept the channel Arc, and the queued reply_tx, alive indefinitely. Receiver::Drop now drains the queue (items dropped after releasing the lock, since a reply_tx drop reaches a different channel's lock + the scheduler), restoring the documented ServerDown guarantee on every teardown path. Adds tests/stop_with_queued_call.rs: deterministic pure-smarm reproducer.
This commit is contained in:
+15
-1
@@ -132,7 +132,21 @@ impl<T> Drop for Sender<T> {
|
||||
|
||||
impl<T> Drop for Receiver<T> {
|
||||
fn drop(&mut self) {
|
||||
self.inner.lock().receiver_alive = false;
|
||||
// The only consumer is gone: queued messages can never be delivered.
|
||||
// Drop them now instead of stranding them until the last Sender goes
|
||||
// away (a registry entry under lazy prune can keep a Sender — and thus
|
||||
// the Arc<Inner> — alive long after the server exits). Dropping a queued
|
||||
// Envelope::Call drops its reply_tx, waking any caller parked in `call`
|
||||
// with ServerDown, so the documented guarantee holds on *every* teardown
|
||||
// path, not only the all-senders-drop one. Drain under the lock, then
|
||||
// run item destructors after releasing it (a reply_tx drop reaches into
|
||||
// a *different* channel's lock + the scheduler, so it must not nest).
|
||||
let drained = {
|
||||
let mut g = self.inner.lock();
|
||||
g.receiver_alive = false;
|
||||
std::mem::take(&mut g.queue)
|
||||
};
|
||||
drop(drained);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user