回来更新新的进程管理模块了:Reload 竞态修复
This commit is contained in:
+23
-71
@@ -1,8 +1,10 @@
|
||||
// internal/frp/legacy.go
|
||||
// Reload 函数适配 P0 改动
|
||||
|
||||
package frp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
@@ -16,10 +18,8 @@ import (
|
||||
|
||||
// ================================================================
|
||||
// 兼容层:保持对外接口不变
|
||||
// 这些函数供 api 调用,实际委托给 process.Manager
|
||||
// ================================================================
|
||||
|
||||
// IsRunning 检查 frpc 是否在运行
|
||||
func IsRunning() bool {
|
||||
pm := process.GetGlobalManager()
|
||||
if pm != nil {
|
||||
@@ -33,7 +33,6 @@ func IsRunning() bool {
|
||||
return isRunningLegacy()
|
||||
}
|
||||
|
||||
// Start 启动 frpc (幂等)
|
||||
func Start() error {
|
||||
pm := process.GetGlobalManager()
|
||||
if pm != nil {
|
||||
@@ -44,7 +43,6 @@ func Start() error {
|
||||
return startLegacy()
|
||||
}
|
||||
|
||||
// Stop 停止 frpc (幂等)
|
||||
func Stop() error {
|
||||
pm := process.GetGlobalManager()
|
||||
if pm != nil {
|
||||
@@ -55,7 +53,6 @@ func Stop() error {
|
||||
return stopLegacy()
|
||||
}
|
||||
|
||||
// Restart 重启 frpc (原子操作)
|
||||
func Restart() error {
|
||||
pm := process.GetGlobalManager()
|
||||
if pm != nil {
|
||||
@@ -69,72 +66,45 @@ func Restart() error {
|
||||
return startLegacy()
|
||||
}
|
||||
|
||||
// GetStatus 获取 frpc 详细状态 (供 API 调用)
|
||||
func GetStatus() (map[string]interface{}, error) {
|
||||
pm := process.GetGlobalManager()
|
||||
if pm != nil {
|
||||
status, err := pm.Status()
|
||||
state, err := pm.Status()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return map[string]interface{}{
|
||||
"state": status.Phase,
|
||||
"pid": status.PID,
|
||||
"port": status.Port,
|
||||
"phase": state.Phase,
|
||||
"pid": state.PID,
|
||||
"port": state.Port,
|
||||
"alive": state.Alive,
|
||||
"frp_ready": state.FRPReady,
|
||||
}, nil
|
||||
}
|
||||
|
||||
running := isRunningLegacy()
|
||||
return map[string]interface{}{
|
||||
"state": map[bool]string{true: "running", false: "stopped"}[running],
|
||||
"phase": map[bool]string{true: "RUNNING", false: "STOPPED"}[running],
|
||||
"pid": 0,
|
||||
"port": 0,
|
||||
"legacy": true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Reload 热加载 frpc 配置
|
||||
// ================================================================
|
||||
// Reload 热加载 frpc 配置(P0 核心)
|
||||
// ================================================================
|
||||
|
||||
func Reload() error {
|
||||
pm := process.GetGlobalManager()
|
||||
if pm == nil {
|
||||
log.Println("[WARN] ProcessManager 未初始化,使用兼容模式 reload")
|
||||
return reloadLegacy()
|
||||
}
|
||||
|
||||
status, err := pm.Status()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 只有在 FAILED 或 STOPPED 时才启动(恢复)
|
||||
// 其他状态(RUNNING、DEGRADED、STARTING)应该执行热加载而不是启动
|
||||
if status.Phase == "FAILED" || status.Phase == "STOPPED" {
|
||||
log.Printf("[DEBUG] Reload: 状态 %s,执行启动恢复", status.Phase)
|
||||
return pm.Start(context.Background())
|
||||
}
|
||||
|
||||
// RUNNING / DEGRADED / STARTING 状态:执行真正的热加载
|
||||
log.Printf("[DEBUG] Reload: 状态 %s,执行配置热加载", status.Phase)
|
||||
|
||||
// 执行 frpc reload 命令
|
||||
frpcPath, err := GetFrpcPath()
|
||||
if err != nil {
|
||||
return fmt.Errorf("获取 frpc 路径失败: %w", err)
|
||||
}
|
||||
|
||||
cmd := exec.Command(frpcPath, "reload", "-c", "./data/frpc.toml")
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
log.Printf("⚠️ 热加载失败 (%v),降级为重启 frpc", err)
|
||||
log.Printf(" reload 输出: %s", string(output))
|
||||
// 降级:重启
|
||||
if err := pm.Restart(context.Background()); err != nil {
|
||||
return fmt.Errorf("重启 frpc 失败: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Printf("✅ frpc 热加载成功: %s", string(output))
|
||||
return nil
|
||||
// 使用 ProcessManager 的 ReloadConfig 方法
|
||||
// 该方法内部处理了 RELOADING 状态和 PID 归属验证
|
||||
log.Println("[INFO] 使用 ProcessManager 执行热加载")
|
||||
return pm.ReloadConfig(context.Background())
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
@@ -150,7 +120,6 @@ func isRunningLegacy() bool {
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if runtime.GOOS == "windows" {
|
||||
cmd := exec.Command("tasklist", "/FI", "PID eq", strconv.Itoa(pid))
|
||||
output, err := cmd.CombinedOutput()
|
||||
@@ -159,12 +128,11 @@ func isRunningLegacy() bool {
|
||||
}
|
||||
return strings.Contains(string(output), strconv.Itoa(pid))
|
||||
}
|
||||
|
||||
proc, err := os.FindProcess(pid)
|
||||
process, err := os.FindProcess(pid)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return proc.Signal(syscall.Signal(0)) == nil
|
||||
return process.Signal(syscall.Signal(0)) == nil
|
||||
}
|
||||
|
||||
func startLegacy() error {
|
||||
@@ -172,45 +140,36 @@ func startLegacy() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := os.MkdirAll("./data", 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := os.Stat("./data/frpc.toml"); os.IsNotExist(err) {
|
||||
if err := GenerateConfig(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if isRunningLegacy() {
|
||||
return nil
|
||||
}
|
||||
|
||||
os.Remove("./data/frpc.pid")
|
||||
|
||||
cmd := exec.Command(frpcPath, "-c", "./data/frpc.toml")
|
||||
setWindowHide(cmd)
|
||||
setSysProcAttr(cmd)
|
||||
|
||||
logFile, err := os.OpenFile("./data/frpc.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cmd.Stdout = logFile
|
||||
cmd.Stderr = logFile
|
||||
|
||||
if err := cmd.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go func() {
|
||||
if err := cmd.Wait(); err != nil {
|
||||
log.Printf("frpc 子进程退出: %v", err)
|
||||
}
|
||||
os.Remove("./data/frpc.pid")
|
||||
}()
|
||||
|
||||
return os.WriteFile("./data/frpc.pid", []byte(strconv.Itoa(cmd.Process.Pid)), 0644)
|
||||
}
|
||||
|
||||
@@ -223,7 +182,6 @@ func stopLegacy() error {
|
||||
os.Remove("./data/frpc.pid")
|
||||
return nil
|
||||
}
|
||||
|
||||
pidData, err := os.ReadFile("./data/frpc.pid")
|
||||
if err != nil {
|
||||
cmd := exec.Command("pkill", "-f", "frpc")
|
||||
@@ -232,18 +190,15 @@ func stopLegacy() error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
pid, _ := strconv.Atoi(strings.TrimSpace(string(pidData)))
|
||||
proc, err := os.FindProcess(pid)
|
||||
process, err := os.FindProcess(pid)
|
||||
if err != nil {
|
||||
os.Remove("./data/frpc.pid")
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := proc.Kill(); err != nil {
|
||||
if err := process.Kill(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
os.Remove("./data/frpc.pid")
|
||||
return nil
|
||||
}
|
||||
@@ -252,12 +207,10 @@ func reloadLegacy() error {
|
||||
if !isRunningLegacy() {
|
||||
return startLegacy()
|
||||
}
|
||||
|
||||
frpcPath, err := GetFrpcPath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmd := exec.Command(frpcPath, "reload", "-c", "./data/frpc.toml")
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
@@ -268,7 +221,6 @@ func reloadLegacy() error {
|
||||
}
|
||||
return startLegacy()
|
||||
}
|
||||
|
||||
log.Printf("✅ frpc 热加载成功 (兼容模式): %s", string(output))
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user