linux通过systemd的timer服务实现定时

背景:每天5个小时执行一次,crontab无法实现。

timer定时器,即使服务器意外重启了,也不会根据timer的执行记录继续循环。

第一天 23:00 ⬅️ 首次
第二天 04:00、09:00、14:00、19:00
第三天 00:00、05:00、10:00、15:00、20:00
第一天 01:00、06:00、11:00、16:00、21:00
第四天 02:00、07:00、12:00、17:00、22:00
第五天 03:00、08:00、13:00、18:00、23:00
第六天 04:00、09:00、14:00、19:00
第七天 00:00、05:00、10:00、15:00、20:00

注:我为方便管理,server文件名必须和timer文件名一致,否则

测试环境:

ubuntu24.04

1.创建server文件

2.创建timer文件

3.启动服务

4.查看管理服务

第一步,创建server服务文件

/etc/systemd/system/《同一自定义服务名》.service

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
[Unit]
Description=每5个小时执行一次
After=network.target

[Service]
#oneshot:仅执行一次
Type=oneshot
#执行路径,注:脚本要添加执行权限!!!
ExecStart=/path/to/your/script.sh
# 或者python直接用命令:ExecStart=/usr/bin/python3 /home/user/myscript.py

第二步,创建timer定时器文件

/etc/systemd/system/《同一义服务名》.timer

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
[Unit]
Description=第一次执行22:59:40,之后每5个小时执行一次

[Timer]
# 首次执行:当天22:59:40(若已过则明天23:00)
OnCalendar=2026-03-25 22:59:40

# 之后每5小时执行一次(基于上次执行时间)
OnUnitActiveSec=5h

# 意外重启不补跑、不生成stamp文件(若错过执行则立即补执行true,忽略则false)
Persistent=false

[Install]
WantedBy=timers.target

第三步,启动服务

systemctl start my-task.timer用于启动定时器,会根据timer中的定义的时间启动脚本,而非立即启动脚本!!!

若想立即启动脚本,则执行systemctl start my-task.server

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 重新加载 systemd 配置
systemctl daemon-reload

# 启用定时器(开机自启)
systemctl enable my-task.timer

# 启动定时器
systemctl start my-task.timer

# 查看定时器状态
systemctl status my-task.timer

第四步,查看管理

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# 查看所有定时器
systemctl list-timers --all

# 查看下次执行时间
systemctl list-timers my-task.timer

# 手动触发server立即执行(测试用)
systemctl start my-task.service

# 查看执行日志
journalctl -u my-task.service -f

# 停止定时器
systemctl stop my-task.timer

# 禁用开机自启
systemctl disable my-task.timer

第五步,重置时间器

1
2
3
4
5
6
7
8
9
# 1. 修改定时器
vi /etc/systemd/system/my-task.timer

# 2. 当Persistent=false时,删除旧的时间记录(必须!)
rm -f /var/lib/systemd/timers/stamp-my-task.timer

# 3. 重启定时器
systemctl daemon-reload
systemctl restart my-task.timer

其它:

systemd OnCalendar 铁律(必背)

只有当 OnCalendar 的时间是「未来时间」时,才会生效并更新下次执行时间。

三种情况的结果:

  1. OnCalendar = 未来时间生效!→ 下次执行时间 = 这个未来时间→ 覆盖原有周期

  2. OnCalendar = 现在 / 过去时间直接忽略!→ 不会触发执行→ 不会改变下次时间

  3. 已经执行过至少一次,且配置了 OnUnitActiveSec=5hOnCalendar 永久失效!→ 之后完全只按 5 小时间隔循环→ 你再怎么改 OnCalendar 到过去时间,都没用了