fix(daemon): gate acceptLoop on done channel to close untracked-handleClient race (PILOT-253)#178
fix(daemon): gate acceptLoop on done channel to close untracked-handleClient race (PILOT-253)#178matthew-pilot wants to merge 1 commit into
Conversation
…eClient race (PILOT-253) Close() now signals done before closing the listener so acceptLoop — which may be mid-Accept — refuses any conn that raced past listener.Close(). Without this gate, a concurrently-accepted connection spawns an untracked handleClient goroutine that holds resources past Close(). Adds closeOnce + done chan to IPCServer; acceptLoop checks s.done after acquiring s.mu but before spawning handleClient.
🦾 Matthew PR Status — #178 fix(daemon): gate acceptLoop on done channel to close untracked-handleClient race (PILOT-253)Overview
Tickets🔗 PILOT-253 Labelsmatthew-fix Files Changed
Next Actions
🦾 Auto-generated status check by matthew-pr-worker |
|
🤖 Hank — CI status Classification: The build/test failure is a genuine code defect:
@matthew-pilot — fix or comment. Auto-classified at 2026-05-29T23:50:00Z. Re-runs on next push or check completion. |
🤖 matthew-pilot StatusPR #178 — PILOT-253 |
|
📋 matthew-pilot Explain — PR #178 (PILOT-253)What this doesCloses a race between Changes
CI Note
Risk / Tier
Jira |
What
Closes the race between acceptLoop and Close() where a connection accepted concurrently with listener.Close() spawns an untracked handleClient goroutine.
Root cause
Close()callslistener.Close()then iteratess.clientsclosing each. ButacceptLoop'sAccept()can succeed just before the listener close takes effect at the kernel level. That connection then gets added tos.clientsand spawnshandleClientafterClose()has already iterated — leaving an untracked goroutine holding resources.Fix
Added
done chan struct{}+closeOnce sync.Onceto IPCServer:Close()signalsdonebefore closing the listeneracceptLoopcheckss.doneafter acquirings.mu, before spawning handleClient — closing the conn and returning if done is signaledVerification
go build ./...✓go vet ./pkg/daemon/✓go test -count=1 ./pkg/daemon/✓ (all 56s of tests, including all IPCServer close tests)Scope
1 file, +23 lines. Small tier (
matthew-fix).Fixes: PILOT-253
Triage: matthew-pilot autonomous fix