Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 5 additions & 11 deletions playground/local_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -283,18 +283,12 @@ func (d *LocalRunner) sendExitError(err error) {
}

func (d *LocalRunner) Stop(keepResources bool) error {
forceKillCtx, cancel := context.WithCancel(context.Background())
defer cancel()
// Keep an eye on the force kill requests.
go func(ctx context.Context) {
select {
case <-ctx.Done():
return
case <-mainctx.GetForceKillCtx().Done():
d.stopAllProcessesWithSignal(os.Kill)
ForceKillSession(d.manifest.ID, keepResources)
}
}(forceKillCtx)
go func() {
<-mainctx.GetForceKillCtx().Done()
d.stopAllProcessesWithSignal(os.Kill)
ForceKillSession(d.manifest.ID, keepResources)
}()
Comment on lines +287 to +291
Copy link
Contributor

Choose a reason for hiding this comment

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

This goroutine will never terminate during normal (non-force-kill) shutdown. The forceKillCtx from mainctx is only cancelled on the 3rd interrupt signal. In the common case (graceful exit), the goroutine blocks on this channel indefinitely.

The previous code used a local context.WithCancel + defer cancel() to ensure the goroutine was cleaned up when Stop() returned. Without that, this goroutine leaks for the remainder of the process lifetime.

Since this is a CLI tool that exits shortly after Stop(), this is practically benign — the leaked goroutine gets cleaned up by process exit. But it's worth noting that the old code was more correct in terms of resource management. If Stop() were ever called in a context where the process continues (e.g., tests, session rotation), the leak would accumulate.

// Kill all the processes ran by playground on the host.
// Possible to make a more graceful exit with os.Interrupt here
// but preferring a quick exit for now.
Expand Down