新的进程回收动作状态机

This commit is contained in:
2026-08-07 23:22:57 +08:00
parent 21d1a4d180
commit 94cd57a459
+44 -5
View File
@@ -486,6 +486,34 @@ func (pm *ProcessManager) killProcess(pid int) error {
return process.Kill()
}
// killAllFrpc 强制杀死所有 frpc 进程(包括孤儿)
func (pm *ProcessManager) killAllFrpc() {
log.Printf("[INFO] 清理所有 frpc 进程...")
if runtime.GOOS == "windows" {
exec.Command("taskkill", "/F", "/IM", "frpc.exe").Run()
} else {
exec.Command("pkill", "-9", "-f", "frpc").Run()
}
time.Sleep(1 * time.Second)
pm.deletePIDFile()
}
// countFrpcProcesses 统计当前 frpc 进程数量
func (pm *ProcessManager) countFrpcProcesses() int {
if runtime.GOOS == "windows" {
cmd := exec.Command("tasklist", "/FI", "IMAGENAME eq frpc.exe")
out, _ := cmd.CombinedOutput()
return strings.Count(string(out), "frpc.exe")
}
cmd := exec.Command("pgrep", "-c", "-f", "frpc")
out, err := cmd.Output()
if err != nil {
return 0
}
count, _ := strconv.Atoi(strings.TrimSpace(string(out)))
return count
}
func (pm *ProcessManager) cleanupOrphans() {
result := pm.CheckPort()
if !result.Ready {
@@ -619,7 +647,6 @@ func (pm *ProcessManager) computeState(pid int, result PortCheckResult) ProcessS
stderr := pm.getLastError()
frpReady := pm.isFRPReady(stdout)
// 获取退出码
pm.exitMu.Lock()
exitCode := pm.exitCode
pm.exitMu.Unlock()
@@ -649,7 +676,6 @@ func (pm *ProcessManager) computeState(pid int, result PortCheckResult) ProcessS
return state
}
// 异常退出
if exitCode != 0 && exitCode != -1 {
state.Error = fmt.Sprintf("进程异常退出 (exit code: %d)", exitCode)
if stderr != "" {
@@ -677,6 +703,11 @@ func (pm *ProcessManager) computeState(pid int, result PortCheckResult) ProcessS
if portReady && frpReady {
state.Phase = PhaseRunning
// 检测多进程
if count := pm.countFrpcProcesses(); count > 1 {
state.Phase = PhaseDegraded
state.Error = fmt.Sprintf("检测到 %d 个 frpc 进程,可能存在多开", count)
}
return state
}
@@ -761,7 +792,12 @@ func (pm *ProcessManager) Start(ctx context.Context) error {
}
defer pm.Unlock()
// 先杀所有 frpc 进程(避免多开)
pm.killAllFrpc()
// 清理孤儿
pm.cleanupOrphans()
return pm.startLocked(ctx)
}
@@ -779,7 +815,6 @@ func (pm *ProcessManager) startLocked(ctx context.Context) error {
pm.startTime = time.Now()
pm.expectedStop = false
// 重置退出码
pm.exitMu.Lock()
pm.exitCode = -1
pm.exitMu.Unlock()
@@ -847,15 +882,18 @@ func (pm *ProcessManager) startLocked(ctx context.Context) error {
time.Sleep(StartupRetryDelay)
}
// 超时:检查进程状态
if pm.isProcessAlive(cmd.Process.Pid) {
stderr := pm.getLastError()
log.Printf("[WARN] frpc 启动超时 (PID: %d),当前 stderr: %s", cmd.Process.Pid, stderr)
// 进程还在但端口没起来,尝试获取 frpc admin API 版本信息
if info := pm.getFRPCStatus(cmd.Process.Pid); info != nil && info.Version != "" {
log.Printf("[INFO] frpc admin API 可访问,版本: %s", info.Version)
// API 可访问说明 frpc 已正常运行,只是端口检测有误
pm.writePIDFile(cmd.Process.Pid)
return nil
}
// 启动失败:杀掉进程
pm.killProcess(cmd.Process.Pid)
pm.deletePIDFile()
return fmt.Errorf("frpc 启动超时: 进程存在但端口未就绪")
}
@@ -957,6 +995,7 @@ func (pm *ProcessManager) HealthCheck() map[string]interface{} {
result["phase"] = state.Phase
result["pid"] = state.PID
result["port"] = state.Port
result["alive"] = state.Alive
result["port_ready"] = state.PortReady
result["frp_ready"] = state.FRPReady