新的进程回收动作状态机
This commit is contained in:
@@ -486,6 +486,34 @@ func (pm *ProcessManager) killProcess(pid int) error {
|
|||||||
return process.Kill()
|
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() {
|
func (pm *ProcessManager) cleanupOrphans() {
|
||||||
result := pm.CheckPort()
|
result := pm.CheckPort()
|
||||||
if !result.Ready {
|
if !result.Ready {
|
||||||
@@ -619,7 +647,6 @@ func (pm *ProcessManager) computeState(pid int, result PortCheckResult) ProcessS
|
|||||||
stderr := pm.getLastError()
|
stderr := pm.getLastError()
|
||||||
frpReady := pm.isFRPReady(stdout)
|
frpReady := pm.isFRPReady(stdout)
|
||||||
|
|
||||||
// 获取退出码
|
|
||||||
pm.exitMu.Lock()
|
pm.exitMu.Lock()
|
||||||
exitCode := pm.exitCode
|
exitCode := pm.exitCode
|
||||||
pm.exitMu.Unlock()
|
pm.exitMu.Unlock()
|
||||||
@@ -649,7 +676,6 @@ func (pm *ProcessManager) computeState(pid int, result PortCheckResult) ProcessS
|
|||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
|
|
||||||
// 异常退出
|
|
||||||
if exitCode != 0 && exitCode != -1 {
|
if exitCode != 0 && exitCode != -1 {
|
||||||
state.Error = fmt.Sprintf("进程异常退出 (exit code: %d)", exitCode)
|
state.Error = fmt.Sprintf("进程异常退出 (exit code: %d)", exitCode)
|
||||||
if stderr != "" {
|
if stderr != "" {
|
||||||
@@ -677,6 +703,11 @@ func (pm *ProcessManager) computeState(pid int, result PortCheckResult) ProcessS
|
|||||||
|
|
||||||
if portReady && frpReady {
|
if portReady && frpReady {
|
||||||
state.Phase = PhaseRunning
|
state.Phase = PhaseRunning
|
||||||
|
// 检测多进程
|
||||||
|
if count := pm.countFrpcProcesses(); count > 1 {
|
||||||
|
state.Phase = PhaseDegraded
|
||||||
|
state.Error = fmt.Sprintf("检测到 %d 个 frpc 进程,可能存在多开", count)
|
||||||
|
}
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -761,7 +792,12 @@ func (pm *ProcessManager) Start(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
defer pm.Unlock()
|
defer pm.Unlock()
|
||||||
|
|
||||||
|
// 先杀所有 frpc 进程(避免多开)
|
||||||
|
pm.killAllFrpc()
|
||||||
|
|
||||||
|
// 清理孤儿
|
||||||
pm.cleanupOrphans()
|
pm.cleanupOrphans()
|
||||||
|
|
||||||
return pm.startLocked(ctx)
|
return pm.startLocked(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -779,7 +815,6 @@ func (pm *ProcessManager) startLocked(ctx context.Context) error {
|
|||||||
pm.startTime = time.Now()
|
pm.startTime = time.Now()
|
||||||
pm.expectedStop = false
|
pm.expectedStop = false
|
||||||
|
|
||||||
// 重置退出码
|
|
||||||
pm.exitMu.Lock()
|
pm.exitMu.Lock()
|
||||||
pm.exitCode = -1
|
pm.exitCode = -1
|
||||||
pm.exitMu.Unlock()
|
pm.exitMu.Unlock()
|
||||||
@@ -847,15 +882,18 @@ func (pm *ProcessManager) startLocked(ctx context.Context) error {
|
|||||||
time.Sleep(StartupRetryDelay)
|
time.Sleep(StartupRetryDelay)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 超时:检查进程状态
|
||||||
if pm.isProcessAlive(cmd.Process.Pid) {
|
if pm.isProcessAlive(cmd.Process.Pid) {
|
||||||
stderr := pm.getLastError()
|
stderr := pm.getLastError()
|
||||||
log.Printf("[WARN] frpc 启动超时 (PID: %d),当前 stderr: %s", cmd.Process.Pid, stderr)
|
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 != "" {
|
if info := pm.getFRPCStatus(cmd.Process.Pid); info != nil && info.Version != "" {
|
||||||
log.Printf("[INFO] frpc admin API 可访问,版本: %s", info.Version)
|
log.Printf("[INFO] frpc admin API 可访问,版本: %s", info.Version)
|
||||||
// API 可访问说明 frpc 已正常运行,只是端口检测有误
|
pm.writePIDFile(cmd.Process.Pid)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
// 启动失败:杀掉进程
|
||||||
|
pm.killProcess(cmd.Process.Pid)
|
||||||
|
pm.deletePIDFile()
|
||||||
return fmt.Errorf("frpc 启动超时: 进程存在但端口未就绪")
|
return fmt.Errorf("frpc 启动超时: 进程存在但端口未就绪")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -957,6 +995,7 @@ func (pm *ProcessManager) HealthCheck() map[string]interface{} {
|
|||||||
|
|
||||||
result["phase"] = state.Phase
|
result["phase"] = state.Phase
|
||||||
result["pid"] = state.PID
|
result["pid"] = state.PID
|
||||||
|
result["port"] = state.Port
|
||||||
result["alive"] = state.Alive
|
result["alive"] = state.Alive
|
||||||
result["port_ready"] = state.PortReady
|
result["port_ready"] = state.PortReady
|
||||||
result["frp_ready"] = state.FRPReady
|
result["frp_ready"] = state.FRPReady
|
||||||
|
|||||||
Reference in New Issue
Block a user