using System; using System.Diagnostics; using System.IO; using System.Threading; namespace EveryPublish.Client.Services; /// 看门狗:spawn agent-core 子进程,5s 心跳检查,失败自动拉起,3 次失败告警 public class Watchdog : IDisposable { private readonly CoreClient _core; private readonly string _dataDir; private readonly Action _onFatal; private Process? _proc; private Timer? _timer; private int _failCount; public Watchdog(CoreClient core, string dataDir, Action onFatal) { _core = core; _dataDir = dataDir; _onFatal = onFatal; } public void Start() { Spawn(); _timer = new Timer(_ => Check(), null, TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(5)); } public void Restart() { try { _proc?.Kill(); } catch { /* 忽略 */ } Spawn(); } private void Spawn() { var exe = Path.Combine(AppContext.BaseDirectory, "agent-core.exe"); if (!File.Exists(exe)) { _onFatal(); return; } var psi = new ProcessStartInfo { FileName = exe, Arguments = "-dir \"" + _dataDir + "\"", WorkingDirectory = Path.GetDirectoryName(exe) ?? AppContext.BaseDirectory, CreateNoWindow = true, UseShellExecute = false, }; _proc = Process.Start(psi); } private void Check() { _core.ReloadLocalJson(); var healthy = false; if (_proc != null && !_proc.HasExited) { try { var status = _core.GetStatusAsync().GetAwaiter().GetResult(); healthy = status != null; } catch { healthy = false; } } if (healthy) { _failCount = 0; return; } _failCount++; if (_failCount >= 3) { _onFatal(); return; } Spawn(); } public void Dispose() { _timer?.Dispose(); try { _proc?.Kill(); } catch { /* 忽略 */ } } }