Skip to content

fix(go): close failed session event loops - #2360

Merged
SteveSandersonMS merged 4 commits into
github:mainfrom
green3sf:agent/close-failed-session-event-loop
Sep 3, 2026
Merged

fix(go): close failed session event loops#2360
SteveSandersonMS merged 4 commits into
github:mainfrom
green3sf:agent/close-failed-session-event-loop

Conversation

@green3sf

Copy link
Copy Markdown
Contributor

Summary

  • stop the eagerly started session event consumer when CreateSession fails
  • centralize local event-channel shutdown so failure cleanup does not issue a session.destroy RPC
  • cover RPC errors, malformed responses, session ID mismatches, and SessionFS initialization failures

Root cause

newSession starts processEvents immediately. The affected error paths removed the pre-registered session from Client.sessions but left its event channel open. Because the failed session was neither returned to the caller nor retained for Client.Stop, its goroutine remained blocked on the channel for the lifetime of the process.

The cleanup now removes only the session instance created by the failing call and closes its event channel without making another RPC.

Impact

Failed non-cloud session creation no longer leaks one goroutine, session object, and buffered event channel per attempt.

Validation

  • go test .
  • go test -race . -run 'TestClient_CreateSession(Failure|InitializationFailure)ClosesRegisteredSession' -count=1
  • git diff --check

Fixes #2320

@green3sf
green3sf marked this pull request as ready for review August 19, 2026 12:43
@green3sf
green3sf requested a review from a team as a code owner August 19, 2026 12:43

@qmuntal qmuntal left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@SteveSandersonMS
SteveSandersonMS force-pushed the agent/close-failed-session-event-loop branch from 868dfc3 to 014be61 Compare September 3, 2026 12:37
green3sf and others added 4 commits September 3, 2026 12:42
ResumeSessionWithOptions pre-registers a session and starts its event
loop before the RPC completes, the same eager-registration pattern
CreateSession has. Every RPC-failure path called restoreReplacedSession
(which correctly restores any session previously registered under this
id, or deletes the map entry) but never closed the new, failed
session's eventCh, leaking its processEvents goroutine per failed call
- the same bug class this PR already fixes for CreateSession.

Adds unit tests mirroring the existing CreateSession coverage.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Real-CLI, no-mocks coverage (goroutine counting across 20 repeated
failures) for both CreateSession and ResumeSession failure paths.
Verified this test fails against the pre-fix code (goroutine count
grows by exactly one per failed call) and passes with the fix
applied.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotSession has the identical eager-background-consumer pattern as
Go: CreateSessionAsync/ResumeSessionAsync register the session and
call StartProcessingEvents() (which starts ProcessEventsAsync() as a
background task) before the RPC completes, but their catch blocks
only called RemoveFromClient() - never completing _eventChannel - so
the consumer task (and the object graph it implicitly keeps alive)
runs forever on every failed call, expressed as a task/GC leak rather
than a goroutine leak.

Adds CopilotSession.CloseEventChannel()/Unregister() and wires both
catch blocks (and DisposeAsync) through them.

Adds a real-CLI E2E test (401 via proxy redirect for CreateSessionAsync,
nonexistent-session-id for ResumeSessionAsync) using reflection to
observe the session dictionary and event-channel completion state
mid-flight, since .NET has no goroutine-count equivalent. Verified
this test fails against the pre-fix code and passes with the fix.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@SteveSandersonMS
SteveSandersonMS force-pushed the agent/close-failed-session-event-loop branch from 014be61 to bcbf151 Compare September 3, 2026 12:52
@SteveSandersonMS
SteveSandersonMS added this pull request to the merge queue Sep 3, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Sep 3, 2026
@SteveSandersonMS
SteveSandersonMS added this pull request to the merge queue Sep 3, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Sep 3, 2026
@SteveSandersonMS
SteveSandersonMS added this pull request to the merge queue Sep 3, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Sep 3, 2026
@SteveSandersonMS
SteveSandersonMS merged commit 4c72ec1 into github:main Sep 3, 2026
62 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Go SDK: CreateSession failure leaks the pre-registered session's processEvents goroutine (non-cloud path)

3 participants