From 78f8b7a0c4125ff2f4ae28bf51ed1f08c8119af9 Mon Sep 17 00:00:00 2001 From: merlinmiao <820962493@qq.com> Date: Tue, 7 Apr 2026 14:43:25 +0800 Subject: [PATCH] fix(gateway): support stop command for externally-started gateway When gateway is started externally and the web handler attaches to it via PID file, the stop command incorrectly returned "not_running" because it only checked gateway.cmd (which is nil for attached gateways). Now handles both cases: 1. Gateway started by handler: uses gateway.cmd.Process 2. Gateway started externally: uses gateway.pidData.PID with os.FindProcess Fixes #2373 Co-Authored-By: Claude Opus 4.6 --- web/backend/api/gateway.go | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/web/backend/api/gateway.go b/web/backend/api/gateway.go index b54e55bac..5436c6828 100644 --- a/web/backend/api/gateway.go +++ b/web/backend/api/gateway.go @@ -452,18 +452,31 @@ func (h *Handler) StopGateway() { // Assumes gateway.mu is held by the caller. // Returns the PID of the stopped process and any error encountered. func stopGatewayLocked() (int, error) { - if gateway.cmd == nil || gateway.cmd.Process == nil { - return 0, nil - } - - pid := gateway.cmd.Process.Pid - - // Send SIGTERM for graceful shutdown (SIGKILL on Windows) + var pid int var sigErr error - if runtime.GOOS == "windows" { - sigErr = gateway.cmd.Process.Kill() + + if gateway.cmd != nil && gateway.cmd.Process != nil { + // Gateway was started by us - use the cmd process + pid = gateway.cmd.Process.Pid + if runtime.GOOS == "windows" { + sigErr = gateway.cmd.Process.Kill() + } else { + sigErr = gateway.cmd.Process.Signal(syscall.SIGTERM) + } + } else if gateway.pidData != nil && gateway.pidData.PID > 0 { + // Gateway was started externally and we attached to it - use os.FindProcess + pid = gateway.pidData.PID + proc, err := os.FindProcess(pid) + if err != nil { + return pid, fmt.Errorf("failed to find process: %w", err) + } + if runtime.GOOS == "windows" { + sigErr = proc.Kill() + } else { + sigErr = proc.Signal(syscall.SIGTERM) + } } else { - sigErr = gateway.cmd.Process.Signal(syscall.SIGTERM) + return 0, nil } if sigErr != nil { @@ -752,7 +765,8 @@ func (h *Handler) handleGatewayStop(w http.ResponseWriter, r *http.Request) { gateway.mu.Lock() defer gateway.mu.Unlock() - if gateway.cmd == nil || gateway.cmd.Process == nil { + // Check if gateway is running (either started by us or attached externally) + if gateway.cmd == nil && gateway.pidData == nil { w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]any{ "status": "not_running",