Skip to content

fix: goroutine leak#41

Merged
zhukaihan merged 3 commits into
mainfrom
fix-stream-goroutine-leak
Mar 4, 2026
Merged

fix: goroutine leak#41
zhukaihan merged 3 commits into
mainfrom
fix-stream-goroutine-leak

Conversation

@zhukaihan
Copy link
Copy Markdown
Collaborator

Summary

Fixes go routine leak if the context is done before channel send, causing go routine to block indefinitely.

Checklist

  • Does your PR title have the correct title format?
  • Does your PR have a breaking change?: no

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes a goroutine leak in the local SSE stream implementation when the context is cancelled before (or around) signaling connect/disconnect/error events, which previously could leave goroutines blocked on unbuffered channel sends.

Changes:

  • Buffer internal signal channels (connectCh, esConnectErrCh, esDisconnectCh) to reduce the risk of blocked sends.
  • Make connect/disconnect callback signaling context-aware via select (removing the previous TOCTOU pattern and eliminating the connect goroutine spawn).
  • Guard the subscribe error path with a select on ctx.Done() to avoid blocking when the main loop has already exited.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread pkg/experiment/local/stream.go Outdated
Comment thread pkg/experiment/local/stream.go Outdated
Comment thread pkg/experiment/local/stream.go Outdated
Comment on lines 139 to 144
client.OnConnect(func(s *sse.Client) {
select {
case <-ctx.Done(): // Cancelled.
return
default:
go func() { connectCh <- true }()
case connectCh <- true: // Non-blocking due to buffer; no goroutine spawn needed.
}
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

There are existing stream_test.go tests, but none appear to cover the specific regression being fixed: context cancellation happening before/around the connect/disconnect callbacks, followed by the callback attempting to signal on the channel. Adding a test that cancels the stream and then invokes onConnCb/onDisCb (asserting it returns promptly and no goroutine is left blocked) would help ensure the leak doesn’t regress.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Can we add a test for this?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Yeah, this is pretty hard to test. Let me see if LLM can get sth.

@zhukaihan zhukaihan merged commit c8912ff into main Mar 4, 2026
4 checks passed
github-actions Bot pushed a commit that referenced this pull request Mar 6, 2026
## [1.10.1](v1.10.0...v1.10.1) (2026-03-06)

### Bug Fixes

* goroutine leak ([#41](#41)) ([c8912ff](c8912ff))
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Mar 6, 2026

🎉 This PR is included in version 1.10.1 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants