当前位置:首页 > 文章列表 > 文章 > linux > systemd 服务怎样用 Type=notify 表达就绪状态

systemd 服务怎样用 Type=notify 表达就绪状态

来源:17golang原创 2026-10-14 14:20:31 0浏览 收藏

有些服务的进程很快就创建出来了,但真正可用还要等待配置加载、缓存预热或监听端口初始化。如果 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。

ExecStart、NOTIFY_SOCKET、READY=1 与 systemd 服务状态的静态关系说明图
图1:Type=notify 与 READY=1 的服务就绪边界说明图,不是终端截图或运行证据。

编写一个会发送 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 配置相互匹配;这不是业务健康检查的替代品。应用仍然需要自己的端口探活、依赖检查或请求级监控。

unit 文件、NotifyAccess=main、READY=1 与 systemctl journalctl 检查对象的静态关系说明图
图2:Type=notify 启动检查对象的静态关系说明图,不是实际运行结果。

常见故障:为什么服务一直没有 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 检查状态,才能把启动依赖关系建立在明确的信号上。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Python Fraction 近似浮点数时怎样控制最大分母Python Fraction 近似浮点数时怎样控制最大分母
上一篇
Python Fraction 近似浮点数时怎样控制最大分母
systemd-analyze critical-chain 怎样定位启动慢的依赖
下一篇
systemd-analyze critical-chain 怎样定位启动慢的依赖
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    471次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    530次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    549次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    499次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    317次使用