如何实现systemd定时任务多次失败仅发送一次通知邮件?
实现单次失败通知的优雅方案
不用手动清理标记文件,我们可以通过拆分systemd服务职责,配合systemd的失败触发机制来解决这个问题:
方案思路
- 主服务仅负责执行SQL刷新脚本,不处理通知逻辑,确保失败状态能被systemd正确捕获
- 创建独立的失败通知服务,仅在主服务首次失败时发送邮件,并记录通知状态
- 主服务成功执行时自动重置通知状态,以便下次失败时能再次触发通知
Ansible配置修改
1. 刷新物化视图的主服务
- name: 添加刷新物化视图的systemd主服务 copy: content: | [Unit] Description=刷新物化视图 Wants=refresh_matviews.timer # 失败时触发通知服务 OnFailure=refresh_matviews-notify.service [Service] User=galaxy Type=oneshot # 仅执行SQL脚本,失败时让systemd捕获退出码 ExecStart=/usr/bin/psql ... -f /path/to/refresh_matviews.sql # 执行成功时,清除通知标记,重置状态 ExecStartPost=/bin/rm -f /var/tmp/refresh_matviews_failed.seen [Install] WantedBy=multi-user.target dest: /etc/systemd/system/refresh_matviews.service owner: root group: root mode: 0644
2. 失败通知服务
- name: 添加失败通知的systemd服务 copy: content: | [Unit] Description=物化视图刷新失败通知 # 仅在主服务失败时触发,且自身为一次性服务 BindsTo=refresh_matviews.service After=refresh_matviews.service [Service] User=galaxy Type=oneshot # 仅当标记文件不存在时,发送邮件并创建标记 ExecStart=/bin/bash -c 'if [ ! -f /var/tmp/refresh_matviews_failed.seen ]; then echo "物化视图刷新失败!" | /usr/bin/mail -s "告警:物化视图刷新失败" admin@foo.com; touch /var/tmp/refresh_matviews_failed.seen; fi' # 禁止自动重启 Restart=no dest: /etc/systemd/system/refresh_matviews-notify.service owner: root group: root mode: 0644
3. 定时服务保持不变
原有的refresh_matviews.timer配置无需修改,依然每5分钟触发主服务。
方案优势
- 无需手动清理标记:主服务成功时自动删除标记文件,下次失败会重新发送通知
- 依赖systemd原生机制:通过
OnFailure触发通知,状态管理更可靠 - 职责分离:主服务专注业务逻辑,通知服务专注告警,架构更清晰
内容的提问来源于stack exchange,提问作者Timur Shtatland
相关产品推荐
相关产品推荐

