进程检测能力调整
This commit is contained in:
+62
-33
@@ -399,7 +399,6 @@ func (pm *ProcessManager) isFRPCProcess(pid int) (bool, string) {
|
||||
// 进程存活检测
|
||||
// ================================================================
|
||||
|
||||
// isProcessAlive 检查 PID 对应的进程是否存活
|
||||
func (pm *ProcessManager) isProcessAlive(pid int) bool {
|
||||
if pid <= 0 {
|
||||
return false
|
||||
@@ -421,6 +420,50 @@ func (pm *ProcessManager) isProcessAlive(pid int) bool {
|
||||
return process.Signal(syscall.Signal(0)) == nil
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// 进程清理
|
||||
// ================================================================
|
||||
|
||||
func (pm *ProcessManager) killProcess(pid int) error {
|
||||
if pid <= 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if runtime.GOOS == "windows" {
|
||||
cmd := exec.Command("taskkill", "/F", "/PID", strconv.Itoa(pid))
|
||||
return cmd.Run()
|
||||
}
|
||||
|
||||
process, err := os.FindProcess(pid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return process.Kill()
|
||||
}
|
||||
|
||||
func (pm *ProcessManager) cleanupOrphans() {
|
||||
// 检查端口是否被占用
|
||||
occupied, err := pm.CheckPort()
|
||||
if err != nil || !occupied {
|
||||
return
|
||||
}
|
||||
|
||||
// 检查是否有 PID 文件
|
||||
pid := pm.readPIDFile()
|
||||
if pid > 0 && pm.isProcessAlive(pid) {
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("[WARN] 检测到孤儿 frpc 进程 (端口 %d 被占用但无有效 PID),正在清理...", pm.adminPort)
|
||||
if runtime.GOOS == "windows" {
|
||||
exec.Command("taskkill", "/F", "/IM", "frpc.exe").Run()
|
||||
} else {
|
||||
exec.Command("pkill", "-f", "frpc").Run()
|
||||
}
|
||||
pm.deletePIDFile()
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// PID 文件操作
|
||||
// ================================================================
|
||||
@@ -532,6 +575,10 @@ func (pm *ProcessManager) Start(ctx context.Context) error {
|
||||
return fmt.Errorf("获取锁失败: %w", err)
|
||||
}
|
||||
defer pm.Unlock()
|
||||
|
||||
// 清理孤儿进程
|
||||
pm.cleanupOrphans()
|
||||
|
||||
return pm.startLocked(ctx)
|
||||
}
|
||||
|
||||
@@ -557,45 +604,28 @@ func (pm *ProcessManager) startLocked(ctx context.Context) error {
|
||||
return fmt.Errorf("启动 frpc 失败: %w", err)
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 组合状态检测:最多等待 5 秒,三条件全部满足才算成功
|
||||
// ============================================================
|
||||
// 立即写入 PID 文件
|
||||
if err := pm.writePIDFile(cmd.Process.Pid); err != nil {
|
||||
log.Printf("[WARN] 写入 PID 文件失败: %v", err)
|
||||
}
|
||||
log.Printf("[DEBUG] frpc 进程已启动,PID: %d", cmd.Process.Pid)
|
||||
|
||||
// 检测端口是否监听(最多 5 秒)
|
||||
for attempt := 0; attempt < StartupMaxAttempts; attempt++ {
|
||||
// 条件1: 检查 PID 文件
|
||||
pid := pm.readPIDFile()
|
||||
if pid <= 0 {
|
||||
time.Sleep(StartupRetryDelay)
|
||||
continue
|
||||
}
|
||||
|
||||
// 条件2: 检查进程是否存活
|
||||
if !pm.isProcessAlive(pid) {
|
||||
time.Sleep(StartupRetryDelay)
|
||||
continue
|
||||
}
|
||||
|
||||
// 条件3: 检查端口是否可连接
|
||||
occupied, err := pm.CheckPort()
|
||||
if err == nil && occupied {
|
||||
// 三项全部满足!
|
||||
pm.writePIDFile(pid)
|
||||
log.Printf("[INFO] frpc 启动成功 (PID: %d, 端口: %d),耗时 %dms",
|
||||
pid, pm.adminPort, attempt*int(StartupRetryDelay/time.Millisecond))
|
||||
cmd.Process.Pid, pm.adminPort, attempt*int(StartupRetryDelay/time.Millisecond))
|
||||
return nil
|
||||
}
|
||||
|
||||
time.Sleep(StartupRetryDelay)
|
||||
}
|
||||
|
||||
// 超时:输出诊断信息
|
||||
pid := pm.readPIDFile()
|
||||
if pid > 0 {
|
||||
alive := pm.isProcessAlive(pid)
|
||||
occupied, _ := pm.CheckPort()
|
||||
return fmt.Errorf("frpc 启动超时: PID=%d, 进程存活=%v, 端口监听=%v", pid, alive, occupied)
|
||||
}
|
||||
|
||||
return fmt.Errorf("frpc 启动超时: 未生成 PID 文件")
|
||||
// 端口监听超时:杀掉启动的进程并清理
|
||||
log.Printf("[WARN] frpc 启动超时 (PID: %d),正在清理...", cmd.Process.Pid)
|
||||
pm.killProcess(cmd.Process.Pid)
|
||||
pm.deletePIDFile()
|
||||
return fmt.Errorf("frpc 启动超时: 端口未监听 (PID: %d)", cmd.Process.Pid)
|
||||
}
|
||||
|
||||
func (pm *ProcessManager) Stop(ctx context.Context) error {
|
||||
@@ -652,8 +682,7 @@ func (pm *ProcessManager) stopLocked(_ context.Context) error {
|
||||
|
||||
// 端口未释放, 强制 kill
|
||||
if runtime.GOOS == "windows" {
|
||||
cmd := exec.Command("taskkill", "/F", "/IM", "frpc.exe")
|
||||
cmd.Run()
|
||||
exec.Command("taskkill", "/F", "/IM", "frpc.exe").Run()
|
||||
} else {
|
||||
proc.Kill()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user