You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ubuntu下systemd托管Python Telegram Bot定时通知重复触发问题

问题根因

这不是systemd缓存配置导致的问题,核心原因是multiprocessing启动的定时任务子进程,在执行systemctl restart bot时没有随主进程一同终止,残留的旧进程持续运行旧版本定时逻辑,最终出现新旧时间点同时触发通知的现象。

systemd服务默认的进程清理逻辑不会主动追踪你通过Python multiprocessing模块fork出的子进程,主进程被终止后,残留的子进程会被init进程收养继续在后台常驻。每修改一次代码重启一次服务,就会多残留一个旧的schedule进程,通知触发次数会随重启次数不断增加。

临时清理:删除所有残留旧进程

先清理当前已经存在的后台残留进程,避免旧任务继续触发:

# 停止当前运行的bot服务
systemctl stop bot
# 杀掉所有bot用户下运行的bot.py相关进程
pkill -u bot -f bot.py
# 执行以下命令无输出即代表清理完成
ps aux | grep bot.py | grep -v grep
永久修复方案

两个方案二选一即可,优先选择方案1,改动成本最低。

方案1:修改systemd服务配置,确保重启时清理所有子进程

编辑bot.service文件,在[Service]段落下新增两行配置:

[Service]
Type=simple
User=bot
WorkingDirectory=/home/bot/tgbot
ExecStart=/usr/bin/python3 /home/bot/tgbot/bot.py
Restart=always
# 新增以下两行配置
KillMode=mixed
TimeoutStopSec=3

配置说明:

  • KillMode=mixed:让systemd在停止服务时,先给主进程发送终止信号,超时后给cgroup内所有剩余子进程发送强制终止信号,彻底避免孤儿进程残留
  • TimeoutStopSec=3:给进程预留3秒的正常退出时间,避免强制终止导致的逻辑异常

配置修改完成后重新加载服务并启动:

systemctl daemon-reload
systemctl start bot

后续执行systemctl restart bot时,所有旧的子进程都会被一并清理,不会再有残留。

方案2:优化代码逻辑,移除不必要的多进程

你的场景不需要单独开多进程运行schedule调度,直接在主进程运行调度逻辑即可从根源上避免子进程残留问题。另外你贴出的代码存在缩进错误、类方法缺少cls/self参数、调度循环位置错误的问题,修正后的参考逻辑如下:

import time
import schedule
# 此处保留你原有bot初始化等业务代码

def send_message():
    bot.send_message(user_ID, 'Message Text')

if __name__ == "__main__":
    # 注册定时任务
    schedule.every().day.at("19:00").do(send_message)
    # 主循环运行调度
    while True:
        schedule.run_pending()
        time.sleep(1)

注意:所有定时任务注册、进程启动类逻辑必须放在if __name__ == "__main__":代码块内,避免multiprocessing fork进程时重复加载执行任务注册逻辑,导致单进程内也出现任务重复触发的问题。

验证方式

修复完成后,可以把定时时间修改为距离当前1-2分钟的时间点,重启服务后等待触发,确认只收到1条通知即代表修复成功,后续改回你需要的通知时间即可。

内容的提问来源于stack exchange,提问作者Friken

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 08:54:21