展厅播放软件崩了怎么自动拉起?进程守护实操
「给核心软件装个看门狗」这句话在运维清单里出现过无数次,但很少有人说清楚这玩意儿具体怎么装。本文补上这一段。文中脚本以 Windows 环境为例,路径与进程名请按你的实际情况替换。
做展厅久了会发现一件事:指望软件永远不崩,是不现实的。播放软件跑一个月不出问题算它争气,可展厅是 365 天连轴转,显卡驱动打个嗝、素材文件读到坏扇区、第三方 SDK 内存泄漏,总有一次让它挂掉。
真正能拉开差距的不是”崩不崩”,而是崩了之后多久能自己起来。没有守护,软件半夜两点崩一次,黑屏就一直挂到第二天早上开馆;有守护,十秒钟自己活过来,观众根本不知道发生过什么。
这篇把进程守护从头讲一遍——怎么判断软件”死了”、怎么把它拉起来、怎么避免拉出更大的乱子。
守护到底在守什么
看门狗的活儿说白了就两步循环:判断目标还活着吗 → 不活了就拉起来。难点全在第一步,因为”活着”有三种口径,越往下越准,也越难做。
第一种:进程名还在不在。 最简单,tasklist 一查就知道。问题是它只能发现”进程没了”这一种死法。
第二种:主窗口句柄还在不在。 比进程名进一步。有些软件崩溃后进程还挂着(变成僵尸),但窗口已经没了,画面自然也没了。查窗口句柄能抓到这一类。
第三种:窗口还响应吗。 最准。程序卡死(无响应白屏)时,进程在、窗口也在,但已经不干活了。这种要靠给窗口发消息看是否超时来判断。
现场怎么选?绝大多数情况下,进程名 + 窗口句柄这两条就够用了,能覆盖八九成的崩溃。第三种”响应性检测”实现复杂,还容易误判——软件正在加载大素材时本来就会短暂无响应,判错了反而把好好的程序杀掉重启,得不偿失。
先动手:一个最简守护脚本
理解了原理,先用十行脚本跑通一遍。新建 guard.ps1:
$exe = 'D:\Player\player.exe'
$name = [System.IO.Path]::GetFileNameWithoutExtension($exe)
while ($true) {
if (-not (Get-Process -Name $name -ErrorAction SilentlyContinue)) {
Write-Host "$(Get-Date -f 'HH:mm:ss') 进程不在,拉起"
Start-Process $exe
}
Start-Sleep -Seconds 10
}
用批处理也行,逻辑一样:
@echo off
:loop
tasklist /fi "imagename eq player.exe" | find /i "player.exe" >nul
if errorlevel 1 start "" "D:\Player\player.exe"
timeout /t 10 /nobreak >nul
goto loop
你应该看到——脚本跑起来后,去任务管理器把 player.exe 结束掉,十秒内它自己又出现了。这就是守护最核心的那点东西,不神秘。
把这个脚本本身加进开机自启(做法见展厅播放设备开机自启与断电恢复设置),一台机的基础守护就成了。
裸重启的坑:重启风暴
上面那个脚本能用,但不能直接拿去上生产。因为它有个致命问题:如果软件是因为”必然失败”的原因起不来——素材盘没挂上、授权过期、配置文件损坏——那它会每隔十秒重启一次,一晚上拉起几千次。
后果不只是日志被刷爆。反复拉起会疯狂占 CPU、疯狂写盘,严重时把机器拖到连远程桌面都连不上,你连救都救不回来,只能第二天跑现场。这叫重启风暴,是自制看门狗最常见的翻车方式。
躲开它要加两道闸:
第一道,指数退避。 别每次都等固定十秒。第一次崩了等 5 秒拉,还崩就等 10 秒、20 秒、40 秒……逐次翻倍,直到某个上限(比如 5 分钟)封顶。这样偶发崩溃能秒恢复,而”必然失败”的情况会自动降频,不至于把机器拖死。
第二道,时间窗限次。 设一个规则:10 分钟内最多拉起 5 次,超了就停手,别再试了,同时把这个状态记下来报给运维。因为连续崩 5 次说明这不是偶发问题,机器自己解决不了,需要人介入。守护的职责是扛偶发故障,不是硬扛配置错误。
改进后的核心逻辑长这样:
$delay = 5 # 当前退避秒数
$max = 300 # 退避上限 5 分钟
$fails = @() # 最近失败时间戳
while ($true) {
if (-not (Get-Process -Name $name -ErrorAction SilentlyContinue)) {
# 清掉 10 分钟以前的记录,只看时间窗内的
$fails = @($fails | Where-Object { $_ -gt (Get-Date).AddMinutes(-10) })
if ($fails.Count -ge 5) {
Write-Host "10 分钟内已拉起 5 次,停止重试,等待人工处理"
Start-Sleep -Seconds 600
$fails = @(); $delay = 5
continue
}
Start-Sleep -Seconds $delay
Start-Process $exe
$fails += (Get-Date)
$delay = [Math]::Min($delay * 2, $max) # 翻倍,封顶
} else {
$delay = 5 # 恢复正常就把退避重置
}
Start-Sleep -Seconds 10
}
这两道闸是自制看门狗和能用的看门狗之间的分界线。如果你只从这篇文章带走一件事,就带走这个。
三条落地路线怎么选
守护逻辑想明白了,落地有三条路,各有各的适用面。
| 方式 | 好在哪 | 代价 | 适合 |
|---|---|---|---|
| Windows 任务计划 | 系统自带,不装东西 | 只能定时轮询,退避限次得自己在脚本里写;会话/权限坑多 | 单台、临时、能接受粗糙 |
| 自己写脚本 | 完全可控,想加什么加什么 | 退避、限次、日志、自启、自身被杀了谁管,全得自己兜 | 有开发能力、场景特殊 |
| 现成代理软件 | 装上配一下就行,坑别人替你踩过了 | 得接受它的配置方式 | 多台点位、要统一管 |
第二条路有个容易被忽略的问题:守护脚本自己崩了谁来守护? 一个 PowerShell 窗口被人误关、或者脚本自身抛异常退出,整套守护就静默失效了,而你完全不知道——直到某天软件崩了没起来。成熟做法是双进程互相保活:两个进程互相盯着对方,谁没了另一个把它拉起来。这东西自己写起来不难,但要写对(避免互相拉起打架、避免同时挂掉)需要花点心思。
第三条路就是省掉这些。我们自研的 SoftAgent 走的是这条:装在被控电脑上,在界面里填程序路径、勾上守护开关就行,崩溃自愈带指数退避 + 时间窗限次(就是上面讲的那两道闸),自身是双进程互相保活。免费版可以守 2 个程序,展厅现场典型就是”播放软件 + 中控客户端”两个关键进程,通常够用。每项还能单独设启动延迟,用来做开机错峰——先起 A,隔十秒再起 B。
配好之后一定要验一遍
守护这东西最怕”配了但没生效”,上线前务必实测:
- 杀进程测试:任务管理器结束目标进程,掐表看多久自恢复;
- 重启测试:重启机器,确认守护自身也跟着自启了(这一步最常漏);
- 风暴测试:把目标程序改个名让它必然起不来,观察是否在若干次后停手,而不是无限重试;
- 误杀测试:确认软件正常加载大素材时不会被守护判死后杀掉。
第二条特别容易栽——守护配得好好的,结果它自己没设开机自启,机器一重启守护就没了,等于裸奔。
常见症状对照
| 症状 | 多半原因 | 怎么办 |
|---|---|---|
| 软件崩了不恢复 | 守护没跑,或没设自启 | 确认守护进程在,且自身已加开机自启 |
| 一晚上重启几千次 | 没有退避和限次 | 加指数退避 + 时间窗限次 |
| 进程在但画面黑 | 只查了进程名,僵尸进程没抓到 | 改查窗口句柄 |
| 加载大素材时被重启 | 用了响应性检测且超时设太短 | 放宽超时,或退回句柄判活 |
| 守护和自启抢着拉起,开了两个实例 | 两套机制重复启动 | 二选一,或给程序加单实例互斥 |
| 拉起来了但没全屏 | 拉起的是程序本身,没恢复播放态 | 让程序自身支持启动即全屏播放 |
最后一条值得多说一句:守护只负责把程序拉起来,拉起来之后能不能自动回到播放状态,取决于程序自己。所以选播控软件时要确认它支持”启动即自动加载片源并全屏”,具体配置见展厅设备开机自动全屏播放配置。
小结
进程守护的核心就三句话:判活优先用进程名 + 窗口句柄,重启必须带退避和限次,守护自己也得有人守。
它在整个无人值守体系里的位置是”最后一道保险”——定时和自启保证展厅能自己开起来,守护保证开起来之后一直不掉链子。三件套的全貌可以看展厅无人值守怎么做;如果现在正卡在”软件根本起不来”,那先按设备开机/自启失败 8 步排查清单把地基修好,再回来加守护。