Linux systemd.service RestartPreventExitStatus 怎样让指定退出码不重启
如果一个长期运行的 Linux 服务大多数异常退出都应该自动拉起,但某个退出码代表“主动结束、等待人工处理”或“配置已经明确失效”,可以把默认重启策略和例外状态拆开配置:用 Restart=on-failure 负责常规恢复,用 RestartPreventExitStatus= 列出不应自动重启的退出码或信号。
本文只讨论 systemd.service 的主服务进程,不把 ExecStartPre=、ExecStop= 等控制命令的退出状态混进来。当前 systemd.service 官方手册地址:https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html。
最小可靠写法是:先给服务设置明确的Restart=,再把需要阻止自动重启的状态写入RestartPreventExitStatus=。该规则只检查服务主进程的退出状态;它不是一个覆盖所有 Exec* 命令的全局失败开关。
先把“默认重启”和“禁止重启”分成两层
Restart=on-failure 表示服务因为非正常退出、信号、超时等情况失败时尝试重启。它解决的是默认策略:大多数故障希望服务回来。RestartPreventExitStatus= 则是例外集合:主服务进程返回其中某个退出码或信号时,即使 Restart= 原本允许重启,也不再自动重启。
例如,应用约定退出码 75 表示“外部依赖暂时不可用但由运维流程接管”,可以把 75 放入禁止列表。这里的数字是应用协议示例,不是 systemd 为所有程序规定的统一含义;systemd 只负责根据主进程实际返回的状态做策略判断。

用最小 service 单元表达退出状态例外
下面的 unit 文件让主服务默认按失败自动重启,但当主进程返回 75 或收到 SIGTERM 时,不再按该规则自动拉起。配置文件中的注释使用 systemd 支持的 # 语法,便于把每个策略的目的留在配置旁边。
[Unit] Description=带退出状态例外的示例服务 [Service] # 这里替换为真实的长期运行程序,示例程序约定 75 是人工接管状态。 ExecStart=/usr/local/bin/example-worker # 普通失败尝试自动恢复,避免一次偶发退出就让服务永久停住。 Restart=on-failure # 主进程返回 75 或被 SIGTERM 终止时,禁止自动重启。 RestartPreventExitStatus=75 SIGTERM # 让日志直接进入 journal,便于和 unit 状态一起查看。 StandardOutput=journal StandardError=journal [Install] # 仅在希望随多用户目标启动时启用该安装关系。 WantedBy=multi-user.target
如果业务只想排除一个数字,就只写这个数字;如果要排除信号,也可以写信号名。不要把应用自己的“正常结束”概念直接套到所有服务上:先在程序文档或退出码约定中确认状态含义,再决定是否加入禁止列表。
修改后按顺序检查配置和状态
将文件保存到例如 /etc/systemd/system/example-worker.service 后,先让 systemd 重新读取 unit 文件,再查看最终内容和关键属性。下面命令只展示检查流程,example-worker 是占位 unit 名称。
# 重新读取 unit 文件;不会自动启动服务。 sudo systemctl daemon-reload # 查看 systemd 当前读取到的完整 unit 内容。 systemctl cat example-worker.service # 只查看重启策略和禁止重启状态,减少人工翻查。 systemctl show example-worker.service \ --property=Restart,RestartPreventExitStatus # 查看当前状态与最近日志,确认失败原因和主进程状态。 systemctl status example-worker.service --no-pager journalctl -u example-worker.service -n 50 --no-pager
daemon-reload 只负责重新读取配置,不等于已经重启服务。真正需要切换进程时,再根据变更窗口选择 systemctl restart;如果只是确认 unit 文本和属性,先不要把检查动作和重启动作混在一起。
| 配置项 | 解决的问题 | 容易误读的地方 |
|---|---|---|
Restart=on-failure | 定义大多数失败退出时的默认恢复动作 | 不是无条件重启,仍受退出原因和限速影响 |
RestartPreventExitStatus=75 | 让主进程返回 75 时跳过自动重启 | 75 的业务含义需要由应用约定,systemd 不替你定义 |
systemctl show | 查看解析后的关键属性 | 看到了配置不代表已经执行了重启 |
只对主服务进程生效,别把 ExecStartPre 当成主进程
RestartPreventExitStatus= 关注的是服务主进程,也就是通常由 ExecStart= 启动、并由 Type= 等设置帮助 systemd 识别的进程。官方手册明确说明,它不作用于 ExecStartPre=、ExecStartPost=、ExecStop=、ExecStopPost= 或 ExecReload=。
[Service] # 预启动命令只是准备步骤,不是 RestartPreventExitStatus 的目标进程。 ExecStartPre=/usr/local/bin/prepare-worker # 这个命令才是长期运行服务的主入口,退出状态会参与重启策略判断。 ExecStart=/usr/local/bin/example-worker # 仅为主进程指定不自动重启的状态。 Restart=on-failure RestartPreventExitStatus=75
因此,如果 ExecStartPre 失败,应该回到该控制命令本身的退出行为、unit 状态和日志判断原因,而不是期待把它的退出码塞进 RestartPreventExitStatus= 就能改变所有启动阶段行为。

退出状态、Restart= 和启动限速要一起看
禁止某个状态重启,不等于所有退出都不会重启;没有命中禁止列表的失败仍按 Restart= 处理。另外,自动重启还受 unit 的启动速率限制影响。若服务短时间内反复失败,StartLimitIntervalSec= 与 StartLimitBurst= 可能让后续启动暂时被限制,这和 RestartPreventExitStatus= 是两个不同层次的问题。
排查时可以按三件事分层:
- 从日志确认主进程到底返回了哪个数字或信号,而不是凭
status=1/FAILURE的展示文字猜测。 - 用
systemctl show对照 systemd 解析后的Restart与RestartPreventExitStatus。 - 如果没有命中禁止列表却仍不重启,再检查启动限速、依赖关系和服务是否被人工停止。
这三层信息能把“退出状态例外”“默认重启策略”“重启次数被限制”区分开,避免单独修改一个参数后得出错误结论。
适合生产的收口方式
我的建议是让退出码语义保持少而稳定:应用只为明确的人工接管、不可自动恢复或需要外部配置修正的场景约定例外码;临时网络抖动、普通依赖失败等仍交给 Restart=on-failure 和日志告警处理。禁止列表越长,自动恢复覆盖面越小,后续维护者越难判断服务为什么停住。
上线前把 unit 文件、退出码约定、回滚文件和告警说明放在同一个变更记录里。验证时先用非生产 unit 名称或维护窗口观察状态,再决定是否启用。不要把本文中的占位路径、退出码和服务名直接复制到生产环境,也不要把“命令已写出”当成“机器已执行”。
RestartPreventExitStatus 可以写多个状态吗?
可以,状态之间用空格分隔,可以混合数字、状态名和信号名。需要重置此前继承或重复配置的列表时,按 systemd.service 手册说明使用空值重置,再写入最终集合。
它会改变服务状态中的退出码含义吗?
不会。它改变的是自动重启决策,不会把数字 75 改名,也不会自动把应用的退出码变成成功。状态含义仍要看程序约定和日志。
为什么服务没有重启,但我没有写 RestartPreventExitStatus?
先检查 Restart= 是否允许该退出原因重启,再检查启动限速、人工停止、依赖失败和 unit 文件是否真的被重新加载。禁止列表只是其中一种原因。
ExecStartPre 返回指定退出码时也会被这个选项拦截吗?
不会。该选项针对主服务进程,控制命令的失败需要通过启动日志、unit 状态和对应的 Exec* 行为单独分析。
最后可以把它记成一句话:Restart= 负责“默认怎么恢复”,RestartPreventExitStatus= 负责“哪些主进程状态例外不恢复”。先确认退出状态来源,再写最小例外集合,配置才不会把可恢复故障和应停机状态混成一团。
Linux systemd.exec OOMScoreAdjust怎样调整服务被 OOM 选择的优先级
- 上一篇
- Linux systemd.exec OOMScoreAdjust怎样调整服务被 OOM 选择的优先级
- 下一篇
- Linux ip route get 怎样按源地址和网卡确认内核选路
-
- 文章 · linux | 52分钟前 | Linux timeout 防火墙规则 nftables sets flags timeout 临时封禁
- Linux nftables sets timeout怎样让临时规则自动过期
- 134浏览 收藏
-
- 文章 · linux | 55分钟前 |
- Linux ethtool ring怎样查看网卡收发环大小
- 264浏览 收藏
-
- 文章 · linux | 57分钟前 |
- Linux ip route get 怎样按源地址和网卡确认内核选路
- 171浏览 收藏
-
- 文章 · linux | 1小时前 |
- Linux systemd.exec OOMScoreAdjust怎样调整服务被 OOM 选择的优先级
- 269浏览 收藏
-
- 文章 · linux | 1小时前 |
- Linux clone3 set_tid怎样为容器初始化进程设置线程 ID
- 119浏览 收藏
-
- 文章 · linux | 1小时前 | Linux 路径安全 openat2 RESOLVE_BENEATH
- Linux openat2 RESOLVE_BENEATH怎样限制路径不能逃逸根目录
- 208浏览 收藏
-
- 文章 · linux | 1小时前 |
- Linux pidfd_send_signal怎样向指定进程安全发送信号
- 423浏览 收藏
-
- 文章 · linux | 1小时前 |
- Linux fanotify怎样监控目录变化并过滤事件
- 484浏览 收藏
-
- 文章 · linux | 1小时前 | 网络编程 · Linux ·
- Linux io_uring multishot accept怎样持续接收连接事件
- 415浏览 收藏
-
- 文章 · linux | 1小时前 |
- Linux io_uring registered files怎样减少高频 I/O 的文件描述符开销
- 120浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 888次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 887次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 970次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 955次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 782次使用
-
- 详解golang执行Linuxshell命令完整场景下的使用方法
- 2023-01-07 426浏览
-
- go程序部署到linux上运行的实现方法
- 2023-01-02 387浏览
-
- Linux系统下Go语言开发环境搭建
- 2023-01-07 242浏览
-
- golang API开发过程的中的自动重启方式(基于gin框架)
- 2023-01-07 454浏览
-
- 使用golang获取linux上文件的访问/创建/修改时间
- 2022-12-31 238浏览
