题记与说明
- 日期:2026-11-04
- 主题 ID:knowledge-fuhydv8g(条目 3)
- 研究方式:主题式网络检索 + 多来源精读 + 本机只读命令实测交叉验证(Windows 11 26200,主机 MAGE,Git Bash)
- 检索词:
Windows service recovery options restart on failure best practices sc.exe failureWindows Task Scheduler vs Windows Service background job which to chooseWindows log rotation logrotate alternative PowerShell rotate application logs scheduled taskwinget upgrade --all scheduled task automate Windows app updates silent
一、来源清单(7 个,全部精读)
| # | 来源 | 类型 | 链接 | 读到的核心内容 |
|---|---|---|---|---|
| S1 | ServerFault: How can I automatically restart a Windows service if it crashes? (2009, 248k views) | 社区问答 | https://serverfault.com/questions/48600/how-can-i-automatically-restart-a-windows-service-if-it-crashes | SCM Recovery 标签页 + sc failure 命令行 + 兜底 watchdog + PowerShell 恢复脚本 |
| S2 | Microsoft Learn(存档): Sc failure 命令参考 | 官方文档 | https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2012-r2-and-2012/cc742019(v=ws.11) | sc failure 完整语法、参数语义、三级动作上限 |
| S3 | NSSM 官方 usage 文档 | 工具文档 | https://nssm.cc/usage | 把任意程序包成服务;内置日志轮转 AppRotate*;指数退避重启 |
| S4 | ServerFault: Windows Service vs. Task Scheduler with startup trigger (2018) | 社区问答 | https://serverfault.com/questions/901388/windows-service-vs-task-scheduler-with-startup-trigger | 服务 vs 计划任务作常驻进程的真实取舍 |
| S5 | CloudBees KB: Log file rotation on Windows | 厂商知识库 | https://docs.cloudbees.com/docs/cloudbees-ci-kb/latest/client-and-managed-controllers/log-file-rotation | "Windows 无原生日志轮转"及两条出路 |
| S6 | Microsoft Learn: winget upgrade 命令(2026-07 更新) | 官方文档 | https://learn.microsoft.com/en-us/windows/package-manager/winget/upgrade | winget upgrade --all 全量选项与坑 |
| S7 | Meziantou: Keeping your software up to date using winget and PowerShell (2023) | 技术博客 | https://www.meziantou.net/keeping-your-software-up-to-date-using-winget-and-powershell.htm | 每天 04:00 的 winget 更新计划任务完整参数 |
说明:StackOverflow 原站(S-O 390307)被反爬拦截(WebFetch 三次 403、webReader 两次只返回元数据),其结论由 S4(ServerFault 同主题问答)替代覆盖;archived 版 sc failure 文档(S2)因现行版 URL 404 而改用官方存档版。二、七维提取
1. 核心问题
个人在 Windows 上把若干程序变成"常年自愈、无人值守的后台服务",要同时回答四个子问题:
- 载体选择:长驻程序用 Windows 服务还是计划任务(startup 触发)?
- 自动恢复:进程崩了/机器重启后,谁能把它自动拉起来,多久拉起来,拉不起来怎么办?
- 日志轮转:写文件的 stdout/应用日志如何不撑爆磁盘(Windows 没有原生 logrotate)?
- 持续更新:服务本体与其依赖软件如何定期升级,且升级不打断服务、不误伤不该动的软件?
2. 主要主张
- 载体二分原则:24/7 常驻、需要内存态/事件监听的进程用 Windows 服务(SCM 提供 Recovery + 依赖管理 + 优雅停止);周期性作业用计划任务(更简单,自带"错过后补跑"等设置)。计划任务加 startup 触发器可以当常驻用(S4 结论:"Yes, in your use case it is"),但要接受三个限制:默认强制结束选项、无任务间依赖、结束=杀进程。
- 自动恢复要三层兜底:
- 第一层:SCM Recovery(
services.msc→ Recovery 标签 /sc failure),三级动作 restart→restart→run(脚本/邮件),配reset=让失败计数定期归零; - 第二层:计划任务自己的 Restart / StartWhenAvailable 设置;
- 第三层:watchdog——每 5 分钟跑一次
net start MyServiceName,"started 就无副作用"。 - 已知坑:服务优雅退出(exit code 0)不触发 SCM 恢复(S1 答 MSS)。
- 第一层:SCM Recovery(
- 日志轮转 Windows 无原生方案(S5 原话:"Windows does not offer a native solution for log rotation"),四条路径按集成度排序:服务包装器自带(NSSM
AppRotate*)→ logrotate 移植(Log-Rotate PS 模块 / LogRotateWin)→ DIY PowerShell 脚本 + 计划任务 → 应用内 rolling logger(NLog/Serilog 等,最可靠,因为由写日志的进程自己切文件)。 - 更新策略:
winget upgrade --all --silent --accept-package-agreements --accept-source-agreements挂每日计划任务(凌晨 4 点)是个人可用的最低成本方案,但必须配:排除清单(例如$_.Id -notlike "TechSmith.*")、预览习惯(先裸跑winget upgrade看清单)、以及对"无版本号应用"与"pinned 应用"的显式开关(--include-unknown/--include-pinned)。服务类软件升级要走 stop → 换二进制 → start,winget 升级会覆盖安装,装完要用第一层 Recovery 把服务拉起来。
3. 方法
- 主题检索:4 组检索词覆盖四个子问题,每组取 1-2 个最权威来源(官方文档优先,其次高票 StackExchange、厂商 KB、可信技术博客)。
- 全文精读:逐来源提取原文引述(见第四节),不做二手转述。
- 本机实测:在 Windows 11 26200 上跑只读命令验证来源说法(见第五节),发现一处中文本地化错误。
- 交叉比对:S4 的"两者都有恢复选项"与 S1/S2 的 SCM 细节互补;S5 与 S3 的日志轮转说法互相印证。
4. 数据与证据
- 引述证据:7 个来源的关键原句(见第四节),含 98 票高票答案的具体配方。
- 本机实测(2026-11-04,主机 MAGE):
sc qfailure Spooler:真实系统服务出厂即带恢复配置——RESET_PERIOD: 3600,两条重启动 -- 延迟 = 5000。证明 SCM Recovery 是系统级通用机制而非理论。sc qc Spooler:START_TYPE: 2 AUTO_START、DEPENDENCIES: RPCSS / http、SERVICE_START_NAME: LocalSystem——服务的自启动、依赖、运行账户三个关键字段。sc failure(无参数)本地用法输出:确认reset=/reboot=/command=/actions=四选项、动作集<run|restart|reboot>、actions=必须与reset=配对。schtasks //query //fo CSV | wc -l→ 430 个任务:计划任务本身就是 Windows 生态的主力调度设施。
- 工具事实:NSSM
AppThrottle默认 1500ms、失败翻倍至约 256000ms(约 4 分钟);AppRotateOnline文档自标 "Danger, moving parts!"。
5. 结论
个人 Windows 服务运维的最小可行栈(按成本从低到高):
- 能是计划任务的就用计划任务:周期作业 + Restart 设置 +
StartWhenAvailable(错过后补跑)+-MultipleInstances IgnoreNew(防重叠)。 - 必须常驻的用"NSSM 包服务 + SCM Recovery":
nssm install <name> <exe路径> # nssm.exe 本体安装后不可移动/删除
nssm set <name> AppStdout D:\logs\app.log
nssm set <name> AppRotateFiles 1
nssm set <name> AppRotateOnline 1
nssm set <name> AppRotateBytes 10485760 # 10MB 轮转
sc failure <name> reset= 86400 actions= restart/60000/restart/60000/run/60000
- watchdog 兜底:计划任务每 5 分钟
net start <name>(对运行中服务无副作用),覆盖"优雅退出 0 不触发恢复"的盲区。 - 日志轮转二选一:优先应用内 rolling logger;无此能力时用 PowerShell 脚本(压缩 N 天前日志、删除超期文件)挂每日计划任务,或直接用 NSSM 的
AppRotate*。 - 更新走 winget 每日任务:04:00、
--silent、两个--accept-*-agreements、显式排除清单;先用裸winget upgrade预览,服务程序升级后确认 Recovery 已把它拉起。
6. 局限
- 来源时效:S1 是 2009 年问答(BLAT 发邮件等细节过时),S2 是官方存档文档;现行版
sc failure页面 URL 404,未能核对最新文档措辞。 - StackOverflow 390307 未读到正文(反爬 403),服务 vs 计划任务的部分结论由 ServerFault 901388 承接,覆盖面略窄。
- 无长周期可靠性数据:所有来源都没有给出恢复机制在真实故障下的成功率统计,"SCM 偶尔不恢复"只有个案陈述(S1 答 MSS:"sometimes auto recover doesn't work correctly")。
- winget 覆盖面:
--include-unknown、--include-pinned的实际副作用(强升 pinned 应用可能破坏依赖)文档未展开;对非 winget 收录的自写服务无能为力,只能走 stop→替换→start 手工管线。 - 中文帮助"微秒"系推断:本机
sc failure帮助写延迟"以微秒计",与官方文档(milliseconds)矛盾;结合 Spooler 实例(延迟 5000 = 明显的 5 秒)判断为本地化错误,但未查到微软官方勘误。 - NSSM 已停更(nssm.cc 最后版本 2.24,2017 年左右),文档仍在但项目不活跃,长期风险未评估。
7. 对我的启发
- nightshift 这类本地自动化栈可以直接套用:
D:/CodexData/nightshift下的夜间任务都是计划任务形态,应给每个任务确认三件事——StartWhenAvailable(机器睡眠/错过触发后补跑)、-MultipleInstances IgnoreNew(防上一轮未完下一轮又起)、日志写出目录有轮转(否则 430 个任务里任何一个失控写盘都会悄悄吃满磁盘)。 - "预览-再全量"习惯:winget 先裸跑
winget upgrade看清单再--all,等价于任何自动化变更的 dry-run;同理sc qfailure <name>永远先于sc failure执行。 - 恢复机制的盲区要写进脚本而不是靠记忆:"优雅退出 0 不触发 SCM 恢复"意味着自写服务应该故意用非零码崩溃或由 watchdog 兜底,这是设计决策而非配置细节。
- 日志轮转在写入方做最可靠:NSSM 的在线轮转自标 "Danger, moving parts!",DIY 脚本又有竞态窗口;如果服务是自己写的,第一选择永远是代码内 rolling logger(按天/按大小切),运维侧轮转只留给改不了的第三方程序。
- 文档本地化错误要实测:
微秒 vs 毫秒这类坑只在真实机器上撞一次才能发现,sc qfailure输出加官方文档对照是廉价有效的验证法。
三、四条子问题的机制细读
3.1 服务管理器与 sc.exe
sc failure 官方语法(S2 存档版全文):
sc [<ServerName>] failure [<ServiceName>] [reset= <ErrorFreePeriod>] [reboot= <BroadcastMessage>]
[command= <CommandLine>] [actions= {"" | {[run/<MS>] | [restart/<MS>] | [reboot/<MS>]}[/...]]四条官方 Remarks(原文见第四节):
- 不是所有服务都允许改失败选项(服务集成员除外);
command=必须用全限定路径(cmd.exe /c D:\xxx.bat或cscript D:\xxx.vbs);actions=最多三个动作,对应第 1、2、3 次失败;=是选项名的一部分,选项与值之间必须有一个空格(actions= restart,漏空格直接失败)。
本机 sc qfailure Spooler 实测显示系统服务出厂即有:1 小时无错误重置计数 + 前两次失败各延迟 5 秒重启。
3.2 计划任务(Task Scheduler / schtasks)
- 任务即进程载体:S4 确认 startup 触发的任务可在无人登录时随开机拉起应用,与服务的区别是语义(任务"预期会结束",且有默认的强制结束选项)与设施(无任务间依赖、结束=杀进程、无 SCM 级恢复标签)。
- 计划任务自己的恢复面:Restart(失败后按间隔重启)、
-StartWhenAvailable(错过的触发点补跑)、-MultipleInstances IgnoreNew、-RunLevel Highest(提权;注册时必须管理员)、-RunOnlyIfNetworkAvailable(S7 全套实测参数)。 - Git Bash 实测坑:
schtasks /query的/query会被 MSYS 路径转换吃掉(报无效参数/选项 - 'C:/Program Files/Git/query'),必须写schtasks //query或MSYS_NO_PATHCONV=1。
3.3 自动恢复的完整决策树
进程死了怎么被拉起?
├─ 是 Windows 服务?
│ ├─ 崩溃退出(非0)→ SCM Recovery: sc failure 三级动作 + reset= 计数重置
│ │ 第3级挂脚本/邮件(command=,需全路径)
│ └─ 优雅退出(0) → SCM 不管 → watchdog: 计划任务每5分钟 net start <name>
│ (对运行中服务是 no-op,见 S1 答 Anderson)
├─ 是 NSSM 包装的服务?
│ └─ NSSM 自己监控子进程并重启(AppExit=Restart 默认);
│ AppThrottle 1500ms 起指数退避至 ~256s,防 crash-loop;
│ SCM Recovery 仍然可用(nssm.exe 本身就是服务程序)
└─ 是计划任务?
└─ 任务设置: Restart on failure + StartWhenAvailable + IgnoreNew
(S4: "Both have options for recovery/restart after failure")3.4 日志轮转四方案对比
| 方案 | 原理 | 优点 | 缺点 | 适用 |
|---|---|---|---|---|
| 应用内 rolling logger | 进程自己按大小/日期切文件 | 零竞态、最可靠 | 要求程序支持 | 自写服务首选 |
NSSM AppRotate* | 服务重启时轮转(AppRotateFiles=1);在线轮转靠管道拦截输出(AppRotateOnline=1) | 零脚本,随服务走 | 在线轮转官方自标 "Danger, moving parts!" 可能丢输出;按字节不按天 | 跑不动的第三方程序 |
| logrotate 移植 | Log-Rotate (PowerShell Gallery) / LogRotateWin,兼容 logrotate.conf 语法 | 配置熟悉、功能全 | 多装一个依赖 | 已熟悉 logrotate 的用户 |
| DIY PowerShell + 计划任务 | 脚本压缩/删除 N 天前日志,每日跑 | 完全可控、无依赖 | 自己处理竞态与保留策略 | 任何场景的兜底 |
S5(CloudBees)的判断是后两者的组合:PowerShell 脚本挂计划任务,或 LogRotateWin("a Windows port of the logrotate utility available for Linux"),并强调这些"not officially supported"。
3.5 更新管线
- 命令面(S6 官方):
winget upgrade(裸跑=预览)、winget upgrade --all、--silent、--include-unknown、--include-pinned、--uninstall-previous、--accept-package-agreements --accept-source-agreements。 - 调度面(S7 实测配方):
New-ScheduledTaskTrigger -At 04:00 -Daily;两个 action(先winget.exe source update再跑脚本);-RunLevel Highest;-MultipleInstances IgnoreNew;-StartWhenAvailable:$true;用Microsoft.WinGet.Client模块Get-WinGetPackage | Where-Object { $_.IsUpdateAvailable }过滤排除清单。 - 语义坑(S6 官方原文):"Some applications do not provide a version. They are always latest." —— 这类应用
--all不带--include-unknown不会升;pinned 应用同理需要--include-pinned。 - 服务程序更新路径:stop 服务 → winget/替换二进制 → start;若更新器直接覆盖安装,靠第一层 Recovery 自动拉起,但配置类变更仍应人工确认。
四、重要原文引述(含中文译)
S1 — Christopher_G_Lewis(98 票,最佳答案):
"View the recovery tab - there are all sorts of options - I'd set First & Second Failure to Restart the Service, Third to run a batch program that BLAT's out an email with the third failure notification. You should also set the Reset Fail Count to 1 to reset the fail count daily."
(看 Recovery 标签页,选项很多——我会把第一、二次失败设为重启服务,第三次设为运行批处理发邮件告警。同时把失败计数重置设为 1 天。)
配命令:
SC failure w3svc reset= 432000 actions= restart/30000/restart/60000/run/60000
SC failure w3svc command= "MyBatchFile.cmd"S1 — MSS(重要坑):
"It seems when service exit gracefully with exit code of 0 windows don't try to recover it."
(服务以退出码 0 优雅退出时,Windows 似乎不会尝试恢复它。)
S1 — Anderson(watchdog 模式):
"execute the below command in windows task scheduler every 5 minutes:net start MyServiceName. This command will basically start the service (if stopped) and has no effect if the service is already running."
(每 5 分钟在计划任务里跑 net start:停了就启动,在跑就无副作用。)
S1 — Nick(Recovery 标签跑 PowerShell 的坑):
"Program: Powershell.exe Not C:\Windows\System32\WindowsPowerShell\v1.0\Powershell.exe"
(Program 字段只填 Powershell.exe,完整路径会导致参数拆分错位。)
S2 — Microsoft Learn 存档(语法与限制):
"You can specify up to three separate actions with the actions= parameter, to be used the first, second, and third times that a service fails."
"For each command-line option (parameter), the equal sign is part of the option name. A space is required between an option and its value (for example, actions= restart). If the space is omitted, the operation will fail."
"Not all services allow changes to their failure options. Some run as part of a service set."
(动作最多三个,对应第 1/2/3 次失败;等号属于选项名,选项与值之间必须有空格,漏了就失败;并非所有服务允许改失败选项。)
S3 — NSSM usage:
"you must not move or delete nssm.exe after installing a service."
(安装服务后不得移动或删除 nssm.exe——nssm 本体被注册为服务程序。)
"AppRotateOnline 1 — rotate files that exceed the size limit while the service runs (nssm intercepts output via a pipe; the docs warn of 'Danger, moving parts!' and possible output loss on failure)"
"AppThrottle (default 1500 ms) — if the app exits sooner than this threshold, nssm pauses before restarting, 'doubling the pause time for each subsequent failure' up to roughly four minutes (256000 ms)"
S4 — apocalysque(受赏 +50 票答案):
"Yes, in your use case it is, however my understanding is that generally the task scheduler expects the task to end at some point (and in fact has a default option to force the task to end if it doesn't end by itself)"
"One area where it's not equivalent is service dependencies. There's no built-in way to make a scheduled task depend on another to run, whereas you can with services."
"Both have options for recovery/restart after failure."
(你的场景可行;但任务调度器预期任务终会结束,且有默认强制结束选项;任务没有服务那种依赖机制;两者其实都有失败恢复选项。)
S4 — Nacht(评论区):
"ending the task in Task Scheduler simply kills the process. If you want built-in stopping functionality, services seem to win here."
(结束计划任务就是直接杀进程;要内置的优雅停止,服务胜出。)
S5 — CloudBees KB:
"Windows does not offer a native solution for log rotation."
"you can use PowerShell to create a logger and run this as a scheduled task within Windows." / "LogRotateWin … a Windows port of the logrotate utility available for Linux."
"The solutions or workarounds described here are not officially supported by CloudBees."
S6 — Microsoft Learn winget upgrade(语义坑):
"Some applications do not provide a version. They are always latest. Because the Windows Package Manager cannot identify if there is a newer version of the app, an upgrade will not be possible unless the -u, --unknown, --include-unknown option is specified."
(无版本号应用在 --all 下默认不升,需要显式 --include-unknown。)
S7 — Meziantou(排除清单与任务参数):
"Where-Object { $_.Id -notlike "TechSmith.*" }"(按包 ID 排除不想自动更新的软件)
任务设置:04:00 每日、-RunLevel Highest、-MultipleInstances IgnoreNew、-RunOnlyIfNetworkAvailable:$true、-StartWhenAvailable:$true、-WakeToRun:$false。
五、本机实测记录(2026-11-04,主机 MAGE,Windows 11 build 26200)
$ sc qfailure Spooler
[SC] QueryServiceConfig2 成功
SERVICE_NAME: Spooler
RESET_PERIOD (以秒计) : 3600
FAILURE_ACTIONS : 重启动 -- 延迟 = 5000 微秒。
重启动 -- 延迟 = 5000 微秒。
(真实系统服务出厂即配好 1 小时计数重置 + 两次重启动作;"微秒"为本地化错误,官方文档为毫秒。)
$ sc qc Spooler
TYPE : 110 WIN32_OWN_PROCESS (interactive)
START_TYPE : 2 AUTO_START
BINARY_PATH_NAME : C:\WINDOWS\System32\spoolsv.exe
DEPENDENCIES : RPCSS / http
SERVICE_START_NAME : LocalSystem$ sc failure
选项:
reset= <重置失败计数为 0 ... 之前无错的时间长度(以秒计)> (必须与 actions= 一起使用)
reboot= <失败时重新启动之前的消息广播>
command= <失败时运行的命令行>
actions= <失败操作和其延迟时间(以微秒计),以 / (斜杠) 分隔 -- 如 run/5000/reboot/800
有效的操作是 <run|restart|reboot> > (必须与 reset= option 一起使用)$ schtasks /query # Git Bash 下报错
错误: 无效参数/选项 - 'C:/Program Files/Git/query'。 ← MSYS 路径转换吃掉了 /query
$ schtasks //query //fo CSV | wc -l → 430 个任务(需用 // 转义)六、综合速查(个人服务运维手册)
新服务上线 checklist:
- 常驻?→
nssm install <name> <exe>;周期作业?→Register-ScheduledTask。 - 日志:应用支持 rolling 就在应用内配;否则
nssm set <name> AppStdout AppRotateFiles 1 AppRotateOnline 1 AppRotateBytes 10485760。 - 恢复:
sc failure <name> reset= 86400 actions= restart/60000/restart/60000/run/60000;自写服务保证崩溃用非零退出码。 - 兜底:计划任务每 5 分钟
net start <name>。 - 计划任务侧三开关:
StartWhenAvailable、-MultipleInstances IgnoreNew、必要的-RunLevel Highest。 - 更新:每日 04:00
winget upgrade --silent --accept-package-agreements --accept-source-agreements+ 排除清单;升级前裸跑winget upgrade预览。 - 自检命令:
sc qfailure <name>、sc qc <name>、schtasks //query //fo LIST //v。
*笔记生成:2026-11-04,精读员·#3。来源均于当日在线精读;本机实测在 Windows 11 26200 上完成。*