From 8280e274d9e2839420f6ef91b3f1c6f76561c537 Mon Sep 17 00:00:00 2001 From: excitedplus1s Date: Fri, 31 Oct 2025 23:51:59 +0800 Subject: [PATCH] fix: close exit channel in Launch method to prevent goroutine leaks --- lib/launcher/launcher.go | 1 + lib/launcher/launcher_test.go | 39 +++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/lib/launcher/launcher.go b/lib/launcher/launcher.go index 4926b376..9d492c59 100644 --- a/lib/launcher/launcher.go +++ b/lib/launcher/launcher.go @@ -443,6 +443,7 @@ func (l *Launcher) Launch() (string, error) { port := l.Get(flags.RemoteDebuggingPort) u, err := ResolveURL(port) if err == nil { + close(l.exit) return u, nil } cmd = exec.Command(bin, args...) diff --git a/lib/launcher/launcher_test.go b/lib/launcher/launcher_test.go index 9414b5dc..8190b506 100644 --- a/lib/launcher/launcher_test.go +++ b/lib/launcher/launcher_test.go @@ -15,6 +15,7 @@ import ( "path/filepath" "strings" "testing" + "time" "github.com/go-rod/rod/lib/defaults" "github.com/go-rod/rod/lib/launcher" @@ -325,3 +326,41 @@ func TestLaunchMultiTimes(t *testing.T) { _, e = l.Launch() g.Eq(e, launcher.ErrAlreadyLaunched) } + +func TestLunchKill_GoroutineLeakCase1(t *testing.T) { + g := setup(t) + dfn := func() { panic("detect goroutine leak") } + g.DoAfter(10*time.Second, dfn) + port := 58472 + l := launcher.New().Leakless(false).RemoteDebuggingPort(port) + dir := l.Get(flags.UserDataDir) + u, e := l.Launch() + g.Neq(u, "") + g.E(e) + l2 := launcher.New().Leakless(false).RemoteDebuggingPort(port) + l2.UserDataDir(dir) + l2.Launch() + l.Kill() + l.Cleanup() + l2.Kill() + // It will hang if goroutine leak is detected. + l2.Cleanup() +} + +func TestLunchKill_GoroutineLeakCase2(t *testing.T) { + g := setup(t) + dfn := func() { panic("detect goroutine leak") } + g.DoAfter(10*time.Second, dfn) + port := 58472 + l := launcher.New().Leakless(false).RemoteDebuggingPort(port) + dir := l.Get(flags.UserDataDir) + u, e := l.Launch() + g.Neq(u, "") + g.E(e) + l2 := launcher.New().Leakless(false).RemoteDebuggingPort(port) + l2.UserDataDir(dir) + l2.Launch() + l2.Kill() + // It will hang if goroutine leak is detected. + l2.Cleanup() +}