Files
Ayay/SHH.CameraService/Core/ParentProcessSentinel.cs
2026-01-16 15:17:23 +08:00

92 lines
3.1 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Ayay.SerilogLogs;
using Microsoft.Extensions.Hosting;
using Serilog;
using SHH.CameraSdk;
using System.Diagnostics;
namespace SHH.CameraService;
/// <summary>
/// 父进程守护服务 (BackgroundService)
/// <para>核心逻辑:定期检查启动本服务的父进程是否存活,若父进程退出(如 UI 崩溃),则触发本服务自动退出,避免孤儿进程占用相机硬件资源。</para>
/// </summary>
public class ParentProcessSentinel : BackgroundService
{
private readonly ServiceConfig _config;
private readonly IHostApplicationLifetime _lifetime;
private ILogger _sysLog = Log.ForContext("SourceContext", LogModules.Core);
/// <summary>
/// 使用统一的结构化日志记录器SourceContext 设置为 Core 模块
/// </summary>
public ParentProcessSentinel(
ServiceConfig config,
IHostApplicationLifetime lifetime)
{
_config = config;
_lifetime = lifetime;
}
/// <summary>
/// 执行后台守护逻辑
/// </summary>
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
int pid = _config.ParentPid;
// 1. 验证 PID 合法性。如果 PID 为 0 或负数,可能是手动启动调试模式,不执行守护逻辑
if (pid <= 0)
{
_sysLog.Warning("[Sentinel] 未指定有效的父进程 PID ({ParentPid}),守护模式已禁用,服务将持续运行.", pid);
return;
}
_sysLog.Information("[Sentinel] 父进程守护已启动,正在监控目标 PID: {ParentPid}", pid);
while (!stoppingToken.IsCancellationRequested)
{
if (!IsParentRunning(pid))
{
_sysLog.Warning("[Sentinel] ### ALERT ### 检测到父进程 (PID:{ParentPid}) 已退出!正在下发系统终止信号...", pid);
// 触发程序优雅退出
_lifetime.StopApplication();
// 强制跳出循环
break;
}
// 每 2 秒检查一次,避免 CPU 浪费
await Task.Delay(2000, stoppingToken);
}
}
/// <summary>
/// 核心状态判定:通过 PID 获取进程快照并检查存活状态
/// </summary>
/// <param name="pid">父进程 ID</param>
/// <returns>存活返回 True已消亡返回 False</returns>
private bool IsParentRunning(int pid)
{
try
{
// 尝试获取进程对象
var process = Process.GetProcessById(pid);
// 检查是否已退出
if (process.HasExited) return false;
return true;
}
catch (ArgumentException)
{
// GetProcessById 在找不到 PID 时会抛出 ArgumentException
// 说明进程已经不存在了
return false;
}
catch (Exception ex)
{
_sysLog.Debug("[Sentinel] 无法定位 PID 为 {ParentPid} 的进程,判定为已退出.", pid);
return true; // 发生未知错误时,保守起见认为它还活着
}
}
}