Make listener teardown exactly-once and bound the accept loop - #12
Open
Atsika wants to merge 1 commit into
Open
Conversation
Two problems in the same lifecycle. A listener whose Accept keeps failing spun forever: it logged on every iteration with no delay while `listener list` still reported Running:true and no agent could ever arrive -- the zombie pattern already fixed in ReceiveLoop. The accept loop now backs off between failures and, after a bounded run of them, tears the listener down and marks it stopped. That gave a second goroutine the ability to stop a listener, and Running, Listener, and CancelFunc were plain fields mutated by StopListener while the CLI read them, with nothing making teardown happen once. Running is now an atomic.Bool claimed with CompareAndSwap, so exactly one of the CLI and the accept loop owns the shutdown, and listener/cancel move behind a mutex with the teardown path factored into teardownListener. Clearing the selected agent and listener stays in StopListener rather than moving into the shared helper: selection is CLI-owned state, and the accept goroutine writing it would trade one race for another. monitorAgent already drops agents without touching selection, so this matches.
Atsika
force-pushed
the
fix/listener-lifecycle
branch
from
August 15, 2026 17:03
a210970 to
08e41e9
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Proxy half of the listener-lifecycle work. The transport half — reporting the Azure deletion window clearly on restart — is Atsika/aznet#6.
Zombie listener. When
Acceptfailed persistently the loop spun with no delay, logging every iteration, whilelistener liststill showedRunning:trueand no agent could arrive. Same pattern that was fixed inReceiveLoop. It now backs off between failures (100ms doubling to 5s) and gives up after 20 consecutive ones, tearing the listener down and marking it stopped.Lifecycle races. Letting the accept loop stop a listener means two goroutines can decide to shut one down, and
Running/Listener/CancelFuncwere plain fields written byStopListenerwhile the CLI read them, with nothing making teardown happen once.Runningis now anatomic.Boolclaimed viaCompareAndSwap, so exactly one caller owns the shutdown;listener/cancelmoved behind a mutex; the shared work is factored intoteardownListener. This also closes the pre-existing double-teardown and CLI-read races.Two ordering choices worth flagging for review:
StopListenerrather than moving into the shared helper. Selection is CLI-owned state, and having the accept goroutine write it would trade one race for another.monitorAgentalready drops agents without touching selection, so this is consistent with what's there.Verified:
go build ./...,go vet ./...,go test ./... -race -count=1, and the wasm agent build, against both the published aznet and the local aznet#6 branch viago.work.