恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

多模块进程常驻管理实战:从nohup到systemd的完整方案

  • 首页
  • 资讯中心
  • /
  • 多模块进程常驻管理实战:从nohup到systemd的完整方案

相关资讯

微信聊天记录结构化导出:从SQLite提取到HTML/Word/CSV三格式交付 2026/10/11 22:18:30
Vastbase G100 V2.2部署运维实战:从选型到避坑全指南 2026/10/11 22:18:30
SC850SL CMOS Sensor手册解读:关键参数、驱动调试与HDR配置 2026/10/11 22:18:30

最新资讯

期货量化策略云端部署实战:从本地迁移到云服务器的完整指南
2026 企业 AI API 聚合平台盘点:国际与国内八大服务商全维度评测
Cheat Engine 6.8.1 源码解析:进程内存扫描与修改原理
rea:用命令行解决碎片笔记管理与检索难题
Playwright实战指南:浏览器自动化核心原理与避坑技巧
Cursor实战:自然语言驱动开发与意图式调试工作流

今日推荐

UE动画修改实战:从资产编辑到重定向与蒙太奇驱动
统计随机数生成器攻击下的KLJN安全密钥交换协议Matlab仿真
政务API安全治理:资产测绘、低代码编排与行标对标实践

本周热门

UE动画修改实战:从资产编辑到重定向与蒙太奇驱动
统计随机数生成器攻击下的KLJN安全密钥交换协议Matlab仿真
政务API安全治理:资产测绘、低代码编排与行标对标实践

本月精选

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)

多模块进程常驻管理实战:从nohup到systemd的完整方案

发布时间:2026/10/11 22:23:31
多模块进程常驻管理实战:从nohup到systemd的完整方案 简介面向系统服务与安卓进程管理的开发者这份资料以双模块工程切入进程常驻实战从守护进程原理到服务绑定、优先级调整均有覆盖适合有一定Java基础并希望深入理解应用保活与系统服务的读者。资源在设计上兼顾理论与实践既有可编译的工程源码也有直观看懂效果的运行截图。压缩包共含六十九个文件以Java源码、XML配置与布局、AIDL接口定义及构建脚本为主配合二十张PNG截图和混淆规则等构建细节完整呈现从进程注册、优先级设置到生命周期管理的实现脉络整体仅十六点九兆离线研读方便。资源由两个模块组成可分别体验前台服务、后台常驻及进程优先级的差异配套工程目录结构清晰便于直接导入开发环境调试与二次开发。内容还对日志监控、自动重启等保活边界作了探讨能帮助读者规避常见误用。已有三百一十九人学习说明其内容对同类需求具有实用参考价值。1. 进程常驻不只是 nohup这份多 module 常驻包解决什么进程常驻这个问题几乎所有做数据采集、消息中转、定时任务的开发者都躲不掉终端一关脚本就跟着死服务器重启后没人记得去点启动器某几个模块各自为战、日志东一处西一处。排障的时候翻三个目录才找得到一份输出文件。这份「进程常驻探索」资源包我完整拆了一遍里面不是一个单一大程序而是把多个业务模块拆开来部署的完整思路每个 module 独立跑、独立给 PID、独立写日志再用 service 体系统一接管。适合手里有 35 个 python 脚本或 shell 任务、想让它们 7x24 小时稳定跑的从业者。这套东西不挑语言核心是启停、守护、日志、自启动这几个常驻必备环节对应到脚本和配置里每一步都能直接抄。2. 常驻方式选型为什么多数人的 nohup 方案撑不到第三天2.1 终端、会话与进程之间的绑定关系先把常驻这件事的原理说透。你在终端里跑一个脚本这个脚本会挂在当前会话下当终端退出时内核会向会话内的进程发送 SIGHUP 信号默认行为是直接终止进程。这就是关终端进程就消失的根本原因。nohup 做的事只是忽略 SIGHUP让进程不至于因为终端退出而被杀。但要注意nohup 并不能解决程序自身崩溃、内存泄漏、死循环、端口被占用后异常退出这类问题。我常跟身边的人讲一句话nohup 是让你把任务“丢出去”而不是把任务“养起来”。真正的常驻需要一个外部机制去监控它、拉起它、记录它的健康状态。这份资源包里的 module 设计方式比较务实每个模块是一个独立的目录目录内有自己的入口脚本和配置对外统一由一套启动管理脚本来调度。这种结构天然适合后面接 systemd 或 supervisor因为每个 service 单元管理一个独立进程不会出现一个挂了拖死一串的情况。2.2 五种常见常驻手段的取舍对比常驻方案的选型直接决定后续的翻车概率。整理一下市面上常用的几种手段方式是否跨终端崩溃自愈开机自启适用场景裸后台 否无无临时任务、前后端联调nohup 是无无一次性长时间任务screen / tmux是弱需手动恢复无交互式运维会话supervisor是有需自配Python 项目常见依赖 pip 环境systemd是有有生产环境首选我自己在真实项目里一般这样选临时跑一个晚上的批量处理用 nohup持续时间超过一周并且希望挂了自动拉起的任务直接上 systemd。资源包里默认提供了对应的 service 配置模板不需要额外安装任何东西。supervisor 我很少用在生产机器上原因是它本身是 Python 包如果机器上有多个 Python 版本或者 conda 环境很容易出现 supervisorctl 连不上 supervisord 的诡异情况排起来比较费劲。2.3 用最小脚本理解 startsid、PID 与日志重定向resource 包里第一个能直接用的是 start_all.sh它做的事情很简单逐个启动 module 目录下的入口脚本记录 PID并把输出重定向到统一的 logs 目录。先看一段简化版#!/bin/bash # 最小化常驻启动示例启动一个名为 collector 的模块 MODULE_NAMEcollector PID_FILE./run/${MODULE_NAME}.pid LOG_FILE./logs/${MODULE_NAME}.log # 检查 PID 文件是否已存在且进程仍在运行 if [ -f $PID_FILE ]; then OLD_PID$(cat $PID_FILE) if kill -0 $OLD_PID 2/dev/null; then echo [skip] $MODULE_NAME 已在运行PID$OLD_PID exit 0 fi fi # 启动新进程setsid 让进程脱离终端会话 setsid python3 ./modules/${MODULE_NAME}/main.py $LOG_FILE 21 NEW_PID$! echo $NEW_PID $PID_FILE echo [ok] $MODULE_NAME 已启动PID$NEW_PID这段脚本四个重点。第一setsid让进程完全脱离当前会话比单纯 nohup 更彻底即使父 shell 退出也不会收到 SIGHUP。第二是追加写日志不会每次启动都覆盖上一次的输出保留现场对排障太重要了。第三PID 文件写入 run 目录这是后面做状态检查和停止操作的基础。第四kill -0只探测进程是否存在不发送信号用于防重复启动。注意这里有个细节$!拿到的其实是 setsid 命令的 PID在大多数 Linux 发行版上 setsid 会 exec 目标程序所以这个 PID 也就是 python 进程本身。个别系统上如果 setsid 没有 exec拿到的会是 setsid 的 PID进程真实 PID 藏在下一个子进程。稳妥的做法是用pgrep -f确认或者用setsid --wait。资源包里面的实际脚本做得更完整加了进程名匹配校验后面有踩坑案例会说。2.4 怎么验证常驻是否真的成功启动之后不能光看“报了个 ok”就收工。我在实际项目里一定会做三层验证# 1. 进程是否存在 ps -ef | grep modules/collector/main.py | grep -v grep # 2. PID 文件里的数字是否与进程一致 cat run/collector.pid ps -p $(cat run/collector.pid) -o pid,stat,cmd # 3. 日志里是否有启动标记 sleep 3 tail -n 20 logs/collector.log第一层验证进程第二层验证 PID 一致第三层验证业务确实跑起来了。如果只做第一层很容易出现进程僵死或者卡在导入阶段ps 能看到但业务完全没动。第三层最关键很多常驻脚本的启动日志是写在业务代码里的比如“connected to server”这类标记看到它才算真正落地。3. 多 module 的资源包组织方式一个任务一个模块崩溃不互拖3.1 为什么拆成多个 module 而不是一个大进程我拿到这套资源的第一反应是看它的目录结构。拆模块而不是堆单体这个设计值得先聊聊。某个图像处理 Demo 里有三个任务图片监听、特征提取、结果上报。三者节奏完全不同监听要实时常驻提取是 CPU 密集上报是网络密集如果写在一个进程里一个模块卡住 I/O 就把全局拖死。把任务拆成独立 module 有四个实际好处。第一崩溃隔离某个模块内存暴涨不会拖垮其他模块。第二日志隔离查问题时只看对应模块的日志文件不用从一堆混着的时间戳里靠 grep 分辨。第三独立重启某个模块发布新版本只要单独重启它其他部分继续服务。第四资源限制后续可以为每个 module 设置独立的 CPU 或内存配额。资源包的目录结构大概长这样直接用 tree 看一下├── modules/ │ ├── collector/ │ │ ├── main.py │ │ └── config.ini │ ├── processor/ │ │ ├── main.py │ │ └── config.ini │ └── reporter/ │ ├── main.py │ └── config.ini ├── run/ # PID 文件存放目录 ├── logs/ # 模块日志统一输出目录 ├── bin/ │ ├── start.sh # 支持按模块启动 │ ├── stop.sh │ ├── status.sh │ └── healthcheck.sh ├── service/ # systemd/supervisor 配置模板 └── README.md这个布局有几个值得抄的地方。run 目录专门放 PID 文件logs 目录专门放日志bin 目录放管理脚本。pid 和日志不要散落到模块目录里否则日志切割、备份、权限管理很麻烦。service 目录放 systemd 配置模板后面会讲怎么用。3.2 start.sh幂等启动的逻辑要点bin/start.sh 是整套资源的入口。它支持三种用法不带参数启动全部模块带模块名启动单个模块带--force强制重启。#!/bin/bash # start.sh幂等启动一个或全部模块 BASE_DIR$(cd $(dirname $0)/.. pwd) RUN_DIR${BASE_DIR}/run LOG_DIR${BASE_DIR}/logs MODULES_DIR${BASE_DIR}/modules # 定义需要常驻的模块列表 MODULES(collector processor reporter) start_module() { local name$1 local pid_file${RUN_DIR}/${name}.pid local log_file${LOG_DIR}/${name}.log mkdir -p $RUN_DIR $LOG_DIR if [ -f $pid_file ]; then local old_pid old_pid$(cat $pid_file) if kill -0 $old_pid 2/dev/null; then echo [skip] $name 已在运行 (PID$old_pid) return 0 else echo [warn] $name 的 PID 文件存在但进程不存在清理残留 rm -f $pid_file fi fi cd ${MODULES_DIR}/${name} || return 1 setsid python3 main.py --config config.ini $log_file 21 local new_pid$! echo $new_pid $pid_file echo [started] $name (PID$new_pid) } if [ $# -eq 0 ]; then for m in ${MODULES[]}; do start_module $m done else start_module $1 fi这段脚本的核心是幂等性。不管你执行多少次 start.sh同一个模块不会启动第二份进程这个判断逻辑靠 PID 文件加上kill -0。如果 PID 文件存在但进程不存在说明上次是异常退出或者机器重启没清干净直接删掉残留后再启动。留意脚本里我用了cd到模块目录再启动这是为了让 python 代码里所有相对路径都以模块目录为基准。很多实际部署中的诡异“文件找不到”问题都是因为从别处执行脚本导致相对路径发生了偏移。3.3 stop.sh优雅退出与超时强杀的配合停止比启动更容易踩坑。直接kill -9是最粗暴的进程持有的数据库连接、临时文件、消息队列状态都有可能写坏。资源包里的 stop.sh 用两段式先发 SIGTERM 让它自己收尾等 N 秒后还没退出再 SIGKILL。#!/bin/bash # stop.sh优雅停止模块超时后强制终止 BASE_DIR$(cd $(dirname $0)/.. pwd) RUN_DIR${BASE_DIR}/run stop_module() { local name$1 local pid_file${RUN_DIR}/${name}.pid if [ ! -f $pid_file ]; then echo [skip] $name 没有 PID 文件无需停止 return 0 fi local pid pid$(cat $pid_file) if ! kill -0 $pid 2/dev/null; then echo [warn] $name 进程($pid)不存在清理 PID 文件 rm -f $pid_file return 0 fi echo [stop] 向 $name (PID$pid) 发送 SIGTERM kill -TERM $pid # 每 0.5 秒检查一次最多等 10 秒 local waited0 while kill -0 $pid 2/dev/null; do sleep 0.5 waited$((waited 1)) if [ $waited -ge 20 ]; then echo [warn] $name 未在 10 秒内退出发送 SIGKILL kill -KILL $pid break fi done rm -f $pid_file echo [ok] $name 已停止 } if [ $# -eq 0 ]; then for pidfile in $RUN_DIR/*.pid; do [ -f $pidfile ] || continue mod_name$(basename $pidfile .pid) stop_module $mod_name done else stop_module $1 fi为什么先 TERM 再 KILL因为业务模块可能在退出前需要写状态文件、关闭数据库连接池、或者通知下游“我要下线了”。有些模块需要处理 SIGTERM 信号来触发收尾逻辑比如 python 代码里注册了signal.signal(signal.SIGTERM, handler)。如果直接 KILL这些逻辑全部被跳过。超时时间我习惯给到 10 秒。太短的话模块收尾逻辑没跑完就强行杀比如 MySQL 事务没提交完就断连数据回滚了。太长的话运维等得着急还可能掩盖死锁问题。10 秒是个相对均衡的值。3.4 日志切割常驻模块最容易被忽视的隐性故障常驻模块的日志文件如果不做切割会无限制增长。日志文件达到几个 GB 之后磁盘被打满系统开始出现各种奇怪的现象文件写不进去、数据库返回磁盘空间不足、甚至整个服务无响应。最常见的原因是进程一直持有文件句柄你用rm删掉日志文件后空间并不释放进程还在往那个已删除的 inode 里写。资源包里带了一份 logrotate 配置模板# /etc/logrotate.d/daemon-modules 的参考配置 ${BASE_DIR}/logs/*.log { daily rotate 7 compress delaycompress missingok notifempty copytruncate create 0644 root root }copytruncate是常驻场景下的关键参数。普通日志切割方式是 rename 旧文件再建新文件但常驻进程还持有旧文件句柄会继续往旧的 inode 写新文件始终是空的。copytruncate 先复制当前内容到新文件再把原文件截断进程继续往原文件写不会断流。代价是复制过程中可能有少量日志丢但对排障来说完全可接受。日志切割之后记得观察一下切割是否真的触发。logrotate 多数发行版是每天由 cron 跑一次跑之前先看一眼/etc/cron.daily/里有没对应脚本。如果你发现日志文件几天没被切割先手动执行/usr/sbin/logrotate -f /etc/logrotate.d/daemon-modules验证配置而不是改完就干等。4. 把 module 纳入 servicesystemd 单元的模板与参数细节4.1 为什么最终要迁到 systemd脚本管常驻有一个天然缺陷机器重启后脚本不会自动执行除非你额外写 crontab reboot 或者 rc.local。而 systemd 作为系统级服务管理器天然解决了开机自启、崩溃重启、日志统一采集三个问题。资源包里的 service 模板就是把前面那些 module 脚本转换成标准的 systemd unit。有人问 supervisor 不也能做吗能但 systemd 不用装。它跟内核同源启动顺序由 init 接管比第三方工具更可靠。唯一要注意的是systemd unit 文件写法有它自己的约束直接套脚本的写法会翻车主要坑在 Type 和 Restart 的选择上。4.2 单模块 unit 文件逐项拆解# /etc/systemd/system/daemon-collector.service [Unit] DescriptionDaemon Collector Module Afternetwork-online.target Wantsnetwork-online.target [Service] Typesimple WorkingDirectory/opt/daemon/modules/collector ExecStart/usr/bin/python3 /opt/daemon/modules/collector/main.py --config config.ini Restartalways RestartSec3 StartLimitIntervalSec0 StandardOutputjournal StandardErrorjournal [Install] WantedBymulti-user.target逐项拆开讲。Typesimple是说 ExecStart 启动的进程本身就是服务主进程不 fork。对于 python 脚本来说这是最合适的因为不需要额外 spawn 子进程。WorkingDirectory必须设置成模块目录否则脚本里相对路径找不到 config.ini。Restartalways代表不管什么原因退出都重启注意它和on-failure的区别如果进程杀了之后退出码是 0on-failure 会认为“干净退出”不重启。但常驻模块正常不该退出一旦退出说明业务中断了所以用 always。RestartSec3是重启前等 3 秒防止崩溃循环里 CPU 被打满。StartLimitIntervalSec0这一行很多人不知道它的含义它关掉了 systemd 对启动失败的次数限制。如果没有这一行默认配置下 10 分钟内启动失败超过 5 次systemd 会拒绝继续尝试你必须手动systemctl reset-failed才能再拉起来。对无人值守的生产模块来说这个限制会导致服务静默死掉所以直接置 0。日志不用再重定向到文件了StandardOutputjournal让 systemd 把进程的标准输出和标准错误都收进 journal用journalctl -u集中查看。4.3 用模板实例减少重复%i 的妙用三个模块就要写三个近乎一样的 unit 文件有没有办法合并systemd 提供了模板单元文件名带符号比如daemon.service启动时用systemctl start daemoncollector来指定实例名。# /etc/systemd/system/daemon.service [Unit] DescriptionDaemon Module %i Afternetwork-online.target [Service] Typesimple WorkingDirectory/opt/daemon/modules/%i ExecStart/usr/bin/python3 /opt/daemon/modules/%i/main.py --config config.ini EnvironmentMODULE_NAME%i Restartalways RestartSec3 StartLimitIntervalSec0 [Install] WantedBymulti-user.target%i在这里会被替换成实际启动的实例名也就是模块目录名。启动方式变成systemctl start daemoncollector开机自启用systemctl enable daemoncollector。模板实例适合模块启动方式一致的场景。如果你的某个模块需要额外传环境变量或者读不同的端口模板会变得别扭。我一般这样把握模块数多且启动参数一致用模板只有两三个模块且差异大老老实实分开写。资源包里两种模板都给了可以直接对照着改。4.4 systemd 下管多模块的常用命令服务配好后日常操作集中在几条命令上。列个表方便粘贴操作命令重载配置systemctl daemon-reload启动systemctl start daemoncollector停止systemctl stop daemoncollector重启systemctl restart daemoncollector开机自启systemctl enable daemoncollector查看状态systemctl status daemoncollector看实时日志journalctl -u daemoncollector -f按时间查日志journalctl -u daemoncollector --since 10 min ago改完 unit 文件之后必须执行daemon-reload否则 systemd 还在用旧配置。我见过不止一次有人改完 RestartSec 不 reload然后反复问“为什么没生效”。另外restart和stop start有细微差别restart 会保留环境变量后者容易因为目录上下文不同产生路径问题。日常发布用 restart排查问题时用 stop 再 start因为能看到干净的启动日志。5. 避坑清单常驻服务翻车最常见的 5 个现场5.1 进程明明在跑业务却静默停机现象ps 能看到 python 进程还在但日志已经几个小时没有新内容下游反馈没数据了。原因业务代码内部有个死循环或者异常被吞了线程卡死但主进程还活着。这类问题 PID 文件和进程存活都发现不了因为从系统角度看进程是“活着”的。解决给业务代码加心跳。最简单的做法是在日志里定期打一个心跳标记比如每 30 秒输出一行heartbeat ok。更好一点是模块内部起一个线程维护状态文件把最近一次成功执行的时间戳写进去。healthcheck 脚本去检查这个时间戳距离当前时间是否超过阈值超过就把进程杀掉让 systemd 重启。资源包里的 healthcheck.sh 就是干这个的#!/bin/bash # 检查模块心跳文件是否仍在更新 HEARTBEAT_FILE/opt/daemon/run/collector.heartbeat MAX_AGE120 # 秒超过 120 秒视为心跳停止 if [ ! -f $HEARTBEAT_FILE ]; then echo [fail] 心跳文件不存在 exit 1 fi last_modified$(stat -c %Y $HEARTBEAT_FILE) now$(date %s) age$(( now - last_modified )) if [ $age -gt $MAX_AGE ]; then echo [fail] 心跳超时age${age}s exit 1 else echo [ok] 心跳正常age${age}s exit 0 fi5.2 开机自启“没生效”连不上的 email 才提醒我现象服务器断电重启后模块没有自动恢复需要手动执行 start.sh 才起来。原因电源恢复后systemd 网络依赖没就绪模块启动时尝试连接数据库失败直接退出触发 Restartalways 后又重试但因为网络栈没完全初始化反复失败。更隐蔽的是 unit 文件没写全Afternetwork-online.targetsystemd 以为网络服务启动了实际还没拿到 IP。解决检查systemctl status daemoncollector里的启动时间和重启次数如果看到很多 Restart 记录说明在启动早期循环失败。unit 文件里把Afternetwork-online.target和Wantsnetwork-online.target写上同时模块内部增加连接重试逻辑不要建连失败就直接退出。DB 连接一般要重试至少 5 次每次间隔 2 秒。5.3 PID 文件与真实进程错位kill 错无辜进程现象stop.sh 时报进程不存在但明明ps -ef | grep main.py能看到一堆相关进程。或者更严重kill 掉一个 PID 后发现杀掉的是别人的进程。原因PID 文件里记录的是旧进程的 PID而旧进程退出后 PID 被系统复用给了其他进程。kill -0发现 PID 有效就以为模块还在运行实际那个 PID 已经不是你的进程。或者启动时用了 shell 管道$!拿到的 PID 和真实 python 进程父进程不一致。解决判定进程是否存活时不能只看 PID还要核对进程名和命令行参数。使用pgrep -f modules/collector/main.py拿到真实进程列表再比对pgrep -f modules/collector/main.py || echo 没有匹配的模块进程同时停止操作应该用 pgrep 结果覆盖 PID 文件里的值而不是盲信文件内容。5.4 systemd 启动失败次数被限制服务被“拉黑”现象某天登录机器发现服务是 inactive (dead) 状态手动 systemctl start 报错类似start request repeated too quickly。原因systemd 默认对单位时间内服务启动失败次数有限制超过后进入 failed 状态不再自动重启。常驻服务如果 config.ini 写错或者依赖的数据库迟迟连不上启动秒退、反复重启就会触发这个策略。解决如 4.2 节所说unit 里加StartLimitIntervalSec0关闭限制。但如果确实想保留限制防止陷入崩溃循环可以设置为StartLimitIntervalSec30配合StartLimitBurst10。另外遇到已经进入 failed 状态的情况先执行systemctl reset-failed daemoncollector清掉失败计数再 start。5.5 日志里全是 traceback但 journal 里一个字看不到现象模块代码里 print traceback 输出到了标准错误但 journalctl 查不到这些内容日志文件里也没有。原因python 的 stdout 和 stderr 默认走不同句柄如果模块代码里自己调用了 logging.basicConfig 把日志指向了某个文件那 systemd 的StandardOutputjournal就接不到任何输出。这是典型的“双写日志”冲突python 内日志进了自己定义的 handler系统层面的重定向失效了。解决代码里不要自行指定 log 文件路径让模块默认输出到 stdout由 systemd 或外层重定向统一接管。或者配置里把日志同时写到文件和 stdout但要维护两处。推荐前者因为 journal 可以按时间、服务名过滤比翻文件舒服太多。实在要写文件记得在 systemd unit 里删掉 StandardOutput 相关字段让进程自己去写别同时又指定又写入造成重复。6. 进阶健康检查与自愈让模块“假装活着”也无法蒙混过关前面 5.1 节讲了心跳文件法下面把它和 systemd 的定时器结合起来做一个完整的自愈闭环。先写一个每分钟执行的检查脚本思路是心跳超时就把对应模块重启重启后如果心跳在 30 秒内恢复说明是临时卡顿如果连续 3 次检查都不恢复发一封报警邮件。#!/bin/bash # healthcheck.sh心跳异常自动重启模块 HEARTBEAT_FILE/opt/daemon/run/${MODULE_NAME}.heartbeat MAX_AGE120 RESTART_LIMIT_FILE/opt/daemon/run/${MODULE_NAME}.restart_count if [ -f $HEARTBEAT_FILE ]; then age$(($(date %s) - $(stat -c %Y $HEARTBEAT_FILE))) if [ $age -le $MAX_AGE ]; then echo [ok] $MODULE_NAME 心跳正常 rm -f $RESTART_LIMIT_FILE exit 0 fi fi echo [warn] $MODULE_NAME 心跳异常准备重启 systemctl restart daemon${MODULE_NAME}配合 systemd timer 来激活比 cron 的优势是 timer 可以设置持久化机器关机错过执行窗口后开机还会补跑# /etc/systemd/system/daemon-healthcheck.service [Unit] DescriptionDaemon Healthcheck [Service] Typeoneshot ExecStart/opt/daemon/bin/healthcheck.sh EnvironmentMODULE_NAMEcollector # /etc/systemd/system/daemon-healthcheck.timer [Unit] DescriptionRun healthcheck every minute [Timer] OnCalendar*:0/1 Persistenttrue [Install] WantedBytimers.target这套做下来常驻模块不仅在崩溃时会自动拉起业务卡死时也会被检测并重启。5.1 到 5.5 那些坑大多都能被这个机制兜住。我自己以前吃过一次大亏某采集模块在死循环里疯狂打日志磁盘写满系统症状表现成“所有服务都变慢”最后查了整整一天才定位到是它在作祟。从那以后我每次部署任何常驻任务都强制走一遍流程心跳文件必须写、健康检查必须挂、日志切割必须验。三样齐了才算上线不然只能算是“跑起来没看住”。这份资源包里的模块结构和脚本正好把这套流程标准化了照着搭一遍就成你自己的常驻骨架希望帮到你。本文还有配套的精品资源点击获取

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号