systemd 服务怎样用 Type=notify 表达就绪状态
有些服务的进程很快就创建出来了,但真正可用还要等待配置加载、缓存预热或监听端口初始化。如果 unit 使用默认的启动语义,systemd 可能把“进程已经运行”误当成“服务已经就绪”。这时可以让服务明确发送 READY=1,再由 Type=notify 接收这个信号。
官方地址:https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html
Type=notify等待服务发出就绪通知,不等同于ExecStart已经启动。- 服务通常通过环境变量
NOTIFY_SOCKET找到 systemd 提供的通知套接字,再发送READY=1。 - 通知应该放在真正完成初始化之后;漏发、发得太早或被
NotifyAccess拒绝,都会让启动状态判断失真。
前置条件:先定义“就绪”是什么
本文用一个最小 Python 服务演示:进程启动后先完成一段初始化,再向通知套接字发送就绪消息。这里的初始化只用短暂等待模拟,实际项目应替换成读取配置、建立连接或加载本地资源等真实动作。
要特别区分两个时刻:ExecStart 表示 systemd 启动了进程,READY=1 才表示应用愿意对外提供服务。若应用没有明确的初始化阶段,使用 Type=simple 反而更直观;不要为了“看起来更完整”机械改成 notify。

编写一个会发送 READY=1 的服务
下面的程序不依赖额外 Python 包,只使用 systemd 注入的 NOTIFY_SOCKET。抽象 Unix 套接字地址以 @ 开头时,需要转换为 Python 可识别的空字节前缀;没有该环境变量时,程序仍能在非 systemd 环境中启动,但不会发送通知。
import os
import socket
import time
def notify_systemd(message: str) -> None:
# 没有被 systemd 监督时,保持示例可直接运行,不把通知当成硬依赖
notify_socket = os.environ.get("NOTIFY_SOCKET")
if not notify_socket:
return
# 把 systemd 的抽象套接字地址转换成 Python 的抽象地址写法
address = notify_socket
if address.startswith("@"):
address = "\0" + address[1:]
# 数据报发送后立即关闭套接字,避免为一次状态通知保留资源
with socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM) as sock:
sock.connect(address)
sock.sendall(message.encode("utf-8"))
def main() -> None:
# 这里模拟配置加载、连接检查等真正决定可用性的初始化工作
time.sleep(2)
# 只有初始化成功后才发送就绪信号
notify_systemd("READY=1\nSTATUS=服务已完成初始化")
# 就绪后进入服务循环;真实项目替换为自己的请求处理逻辑
while True:
time.sleep(10)
if __name__ == "__main__":
# 保留标准入口,便于 ExecStart 直接启动本文件
main()
这个例子里最关键的不是等待两秒,而是通知位置。若把 READY=1 放在初始化前面,systemd 会过早把服务视为已就绪;若初始化失败就直接退出,则不应发送成功信号。
配置 Type=notify 和 NotifyAccess=main
接着创建一个 unit 文件。NotifyAccess=main 明确表示只接受主进程发出的通知;本例由 ExecStart 启动的 Python 进程自己发送,所以边界清楚,也方便后续排查。
[Unit] Description=Type notify demonstration service After=network.target [Service] # 只有收到 READY=1 后,启动状态才表示应用已就绪 Type=notify # 本例由 ExecStart 主进程发送通知 NotifyAccess=main ExecStart=/usr/bin/python3 /opt/notify-demo/service.py Restart=on-failure # 防止初始化永远不发送 READY=1 而无限等待 TimeoutStartSec=30 [Install] WantedBy=multi-user.target
把文件保存为 /etc/systemd/system/notify-demo.service,把脚本保存为 /opt/notify-demo/service.py 后,再让 systemd 重新读取 unit。示例路径只是部署位置的约定,生产环境应替换为实际路径,并确认执行用户对脚本和依赖资源有权限。
# 让 systemd 重新读取新增或修改后的 unit 文件 sudo systemctl daemon-reload # 启动服务并设置为开机启动;这一步会改变机器状态 sudo systemctl enable --now notify-demo.service # 查看服务的高层状态和子状态,确认是否已经离开 activating systemctl show notify-demo.service -p ActiveState -p SubState -p Type
运行后怎样检查是否真的就绪
检查时不要只看进程是否存在。先看 systemd 当前记录的状态,再看日志中是否有应用初始化失败或启动超时。通知成功时,服务通常会从 activating 进入 active;如果一直停留在前者,优先检查是否到达了发送 READY=1 的代码路径。
# 只读取当前状态,不改变服务配置 systemctl is-active notify-demo.service systemctl show notify-demo.service -p ActiveState -p SubState -p ExecMainStatus # 查看本次启动日志,重点关注初始化异常和超时提示 journalctl -u notify-demo.service -b --no-pager -n 80
如果示例服务启动后保持运行并进入 active/running,只能说明它的通知路径和 unit 配置相互匹配;这不是业务健康检查的替代品。应用仍然需要自己的端口探活、依赖检查或请求级监控。

常见故障:为什么服务一直没有 ready
| 现象 | 优先检查 | 处理思路 |
|---|---|---|
| 一直处于 activating | 初始化分支是否真正调用了通知函数 | 把 READY=1 放在成功初始化之后,并查看启动日志 |
| 启动超时后失败 | TimeoutStartSec 与实际初始化耗时 | 先修复卡住或失败的初始化,再按业务需要调整超时 |
| 通知由子进程发送却不生效 | NotifyAccess 是否允许发送者 | 让主进程统一发送,或按 systemd 文档明确配置允许范围 |
| 改完 unit 仍像旧配置 | 是否执行过 daemon-reload | 重新加载后再重启服务,并区分 unit 读取问题与应用通知问题 |
排查顺序建议固定为“通知环境变量、发送时机、发送进程、unit 重载、日志结果”。不要先把超时调得很大来掩盖漏发通知;那只会让依赖方更晚发现服务并未就绪。
清理与回滚
如果只是实验,先停止并禁用服务,再删除自建 unit 和脚本;删除前确认路径确实是本次实验创建的文件。若要回滚到普通启动语义,则应同时移除应用里的通知代码,并把 unit 的 Type=notify 改回与你的进程行为匹配的类型,不能只改其中一侧。
# 停止并取消开机启动,避免实验服务继续运行 sudo systemctl disable --now notify-demo.service # 删除本实验创建的 unit 文件后重新加载配置 sudo rm /etc/systemd/system/notify-demo.service sudo systemctl daemon-reload
常见问题
Type=notify 和 Type=simple 有什么区别?
Type=simple 通常把进程启动视作服务启动完成;Type=notify 则要求服务主动发送就绪通知。选择哪一个取决于应用是否有可识别且值得暴露给服务管理器的初始化完成点。
READY=1 应该发送几次?
通常在一次启动的初始化成功点发送一次即可。重点是发送时机和发送者权限,不是反复发送来“保活”;持续存活和看门狗属于另一套机制。
没有 systemd 时这个 Python 示例能运行吗?
可以运行主循环,因为示例在没有 NOTIFY_SOCKET 时直接跳过通知;但此时没有 systemd 服务状态可以接收 READY=1。这正是把通知设计成可选环境能力的好处。
总结一下:Type=notify 的价值是把“进程已启动”和“应用已就绪”拆开。让主进程在真实初始化成功后通过 NOTIFY_SOCKET 发送 READY=1,再用 systemctl show 与 journalctl 检查状态,才能把启动依赖关系建立在明确的信号上。
Python Fraction 近似浮点数时怎样控制最大分母
- 上一篇
- Python Fraction 近似浮点数时怎样控制最大分母
- 下一篇
- systemd-analyze critical-chain 怎样定位启动慢的依赖
-
- 文章 · linux | 42分钟前 |
- Linux shell 管道失败状态怎样向上返回
- 290浏览 收藏
-
- 文章 · linux | 46分钟前 |
- Linux cron 和 systemd timer 怎样选择
- 192浏览 收藏
-
- 文章 · linux | 50分钟前 | 内存管理 · 日志排查 · Linux pid journalctl 内核日志 dmesg cgroup 内存排障 OOM Killer
- Linux OOM killer 怎样从日志确认触发对象
- 131浏览 收藏
-
- 文章 · linux | 51分钟前 | Linux IPC 性能诊断 perf stat CPU指标 cycles instructions cache-misses
- Linux perf stat 怎样先看 CPU 指标
- 110浏览 收藏
-
- 文章 · linux | 53分钟前 | Linux 僵尸进程 SIGCHLD PID namespace init进程 孤儿进程 waitpid
- Linux PID namespace 中 init 进程怎样回收子进程
- 206浏览 收藏
-
- 文章 · linux | 55分钟前 |
- Linux TCP backlog 怎样区分监听队列和连接队列
- 407浏览 收藏
-
- 文章 · linux | 1小时前 |
- Linux journalctl 怎样按优先级筛出启动错误日志
- 326浏览 收藏
-
- 文章 · linux | 1小时前 | Linux · Linux fanotify FAN_OPEN_PERM FAN_ACCESS_PERM
- Linux fanotify 权限事件的允许与拒绝处理方案
- 489浏览 收藏
-
- 文章 · linux | 1小时前 | 服务管理 · Linux systemd systemd-analyze critical-chain 服务依赖 启动排障
- systemd-analyze critical-chain 怎样定位启动慢的依赖
- 113浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 471次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 530次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 549次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 499次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 317次使用
-
- 详解CentOS7下PHP+Nginx+Mysql编译安装方法
- 2023-01-21 432浏览
-
- MySQL mysqldump --single-transaction 导出 InnoDB:一致性边界与锁影响
- 2026-08-27 273浏览
-
- Linux 服务启动失败怎么查:状态和日志的排查顺序
- 2026-07-15 195浏览
-
- Linux 业务服务部署怎么选:服务单元与 Docker Compose 的启动、恢复与回滚取舍
- 2026-07-19 473浏览
-
- Linux 服务重启后找不到 PATH 怎么办:EnvironmentFile、登录 Shell 和启动日志排查
- 2026-07-20 187浏览
