From 1598c4b8b9753093ab94b6518bf0f7047b090328 Mon Sep 17 00:00:00 2001 From: Chris Lu Date: Mon, 22 Dec 2025 00:37:48 -0800 Subject: [PATCH] Ensure stream errors are never lost by using async fallback When handleIncoming detects a stream error, queue ActionStreamError to managerLoop with non-blocking send. If managerLoop is busy and cmds channel is full, spawn an async goroutine to queue the error asynchronously. This ensures the manager is always notified of stream failures, preventing the connection from remaining in an inconsistent state (connected=true while stream is dead). --- weed/worker/client.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/weed/worker/client.go b/weed/worker/client.go index 2545ef5d8..27633ecdb 100644 --- a/weed/worker/client.go +++ b/weed/worker/client.go @@ -456,11 +456,16 @@ func handleIncoming( default: } - // Report the failure as a command to the managerLoop (non-blocking to prevent deadlock) + // Report the failure as a command to the managerLoop. + // Try non-blocking first; if the manager is busy and the channel is full, + // fall back to an asynchronous blocking send so the error is not lost. select { case cmds <- grpcCommand{action: ActionStreamError, data: err}: default: - glog.V(2).Infof("Manager busy, stream error not queued: %v", err) + glog.V(2).Infof("Manager busy, queuing stream error asynchronously: %v", err) + go func(e error) { + cmds <- grpcCommand{action: ActionStreamError, data: e} + }(err) } // Exit the main handler loop