Repository navigation
Fix browser test goroutine leak on cleanup - #5643
Conversation
The browser registry spawns handleIterEvents and handleExitEvent goroutines per VU, which block on channel receives. These channels are only closed when an Exit event is emitted, but the test VU never emitted one. This caused goroutines to leak across tests, accumulating hundreds of stuck goroutines and eventually causing the browser test suite to exceed its timeout. Emit an Exit event on the Global event system during test cleanup, which triggers handleExitEvent -> unsubscribe -> channel close, allowing both goroutines to exit cleanly. Co-authored-by: Cursor <cursoragent@cursor.com>
3dfdedb to
842c506
Compare
| waitDone := globalEvents.Emit(&event.Event{ | ||
| Type: event.Exit, | ||
| }) | ||
| _ = waitDone(context.Background()) |
There was a problem hiding this comment.
I didn't review yet in detail. But I assume this line means wait indefinitely. Can we have a time-limited context so it will time out at some point? or alternatively tb.Context()
There was a problem hiding this comment.
Yeah, good spot. If you follow the code path to what the exit event does it will eventually call this. From there it looks like it's pretty straight forward local executions (no IO or long running tasks), i guess there's potential to some sync contention though when trying to close the tracer, but apart form that it doesn't look computationally heavy.
What i'm trying to get at is that I don't think we need a timeout, and if something does go wrong and we're waiting indefinitely then it might be better to surface it?
If you have a strong opinion then i can change it to a context with timeout with 5 seconds.
There was a problem hiding this comment.
we're waiting indefinitely then it might be better to surface it?
I changed my mind, I agree with it 🤝
What?
Fixes a goroutine leak when running the browser tests. Emit an
Exitevent on the Global event system during test cleanup, which triggers handleExitEvent -> unsubscribe -> channel close, allowing both goroutines to exit cleanly.Why?
The browser registry spawns
handleIterEventsandhandleExitEventgoroutines per VU, which block on channel receives. These channels are only closed when an Exit event is emitted, but the test VU never emitted one. This caused goroutines to leak across tests, accumulating hundreds of stuck goroutines and eventually causing the browser test suite to exceed its timeout.This should:
Goroutine leak comparison (800s timeout)
browserRegistry.handleIterEventsbrowserRegistry.handleExitEventBaseEventEmitter.syncAllBrowser.initEventsConnection.sendLoopConnection.handleIOErrorBrowserProcess.handleCloseNetworkManager.handleEventsThe 679 leaked
handleIterEvents/handleExitEventgoroutine pairs (one pernewTestBrowsercall) are completely eliminated. The remaining single instance of each is from the actively running test at timeout. The remaining 47 goroutines are from a separate leak in tests that create browser connections without closing them (addressed in a follow-up PR).Checklist
make check) and all pass.AI tool usage
Checklist: Documentation (only for k6 maintainers and if relevant)
Please do not merge this PR until the following items are filled out.
Related PR(s)/Issue(s)