mirror of
https://github.com/chainreactors/spray.git
synced 2026-10-29 11:50:52 +00:00
Root cause: the atomic.Bool + polling monitor goroutine pattern had a race between wg.Wait() in the monitor and wg.Add(1) in the main loop. When the monitor observed done=true and started Wait, the main loop could still dispatch new work, causing Close().wg.Wait() to hang. Fix: replace with nil-channel + sync.Once pattern. When the word stream exhausts or limit is hit, worderCh is set to nil (disabling that select branch permanently), then a single goroutine waits for wg to reach zero. Since wg.Add(1) only occurs in the worderCh branch, nil-ing it before Wait guarantees no new Add after Wait starts — no race possible. Other fixes: - Task feeder goroutine now ctx-aware (prevents leak on cancel) - AddPool checks Invoke error (prevents poolwg counter mismatch) - Revert resource_provider IIFE (reading a struct field cannot panic) - Remove E2E -short skip (race is fixed, full coverage in CI) - Fix Go 1.24+ vet: non-constant format strings in Init() Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>