fix: Windows-specific reliability gap in the new timeout cleanup path (#74703)

Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
This commit is contained in:
clawsweeper[bot]
2026-04-29 22:43:09 -07:00
committed by GitHub
parent 0c74952bcf
commit 897ca6abbb
2 changed files with 77 additions and 1 deletions

View File

@@ -2,8 +2,35 @@
package main
import "os/exec"
import (
"context"
"errors"
"os"
"os/exec"
"strconv"
)
var runWindowsTaskkill = func(pid int) error {
ctx, cancel := context.WithTimeout(context.Background(), docsI18nCommandWaitDelay())
defer cancel()
return exec.CommandContext(ctx, "taskkill.exe", "/T", "/F", "/PID", strconv.Itoa(pid)).Run()
}
func configureCodexPromptCommand(command *exec.Cmd) {
command.Cancel = func() error {
if command.Process == nil {
return os.ErrProcessDone
}
if err := runWindowsTaskkill(command.Process.Pid); err != nil {
killErr := command.Process.Kill()
if errors.Is(killErr, os.ErrProcessDone) {
return os.ErrProcessDone
}
if killErr != nil {
return errors.Join(err, killErr)
}
}
return nil
}
command.WaitDelay = docsI18nCommandWaitDelay()
}

View File

@@ -0,0 +1,49 @@
//go:build windows
package main
import (
"errors"
"os"
"os/exec"
"testing"
"time"
)
func TestConfigureCodexPromptCommandWindowsCancelsProcessTree(t *testing.T) {
t.Setenv(envDocsI18nCommandWaitDelay, "25ms")
previousRunTaskkill := runWindowsTaskkill
defer func() { runWindowsTaskkill = previousRunTaskkill }()
var gotPID int
runWindowsTaskkill = func(pid int) error {
gotPID = pid
return nil
}
command := exec.Command("codex")
configureCodexPromptCommand(command)
command.Process = &os.Process{Pid: 1234}
if command.WaitDelay != 25*time.Millisecond {
t.Fatalf("expected WaitDelay override, got %s", command.WaitDelay)
}
if command.Cancel == nil {
t.Fatal("expected Cancel to be configured")
}
if err := command.Cancel(); err != nil {
t.Fatalf("Cancel returned error: %v", err)
}
if gotPID != 1234 {
t.Fatalf("expected taskkill for pid 1234, got %d", gotPID)
}
}
func TestConfigureCodexPromptCommandWindowsCancelBeforeStart(t *testing.T) {
command := exec.Command("codex")
configureCodexPromptCommand(command)
if err := command.Cancel(); !errors.Is(err, os.ErrProcessDone) {
t.Fatalf("expected os.ErrProcessDone, got %v", err)
}
}