systemd (简体中文)/Timers (简体中文)
Timers 是以 .timer 为后缀名的 systemd 单元文件,用于控制 .service 文件或事件。Timers 可用来替换 cron(阅读 #替代 cron)。Timers 内置了实时定时事件和单调定时事件的支持,并可以异步执行这些事件。
定时器单元
Timers 是以 .timer 为后缀的 systemd 单元文件。Timers 和其他单元配置文件是类似的,它通过相同的路径加载,不同的是包含了 [Timer] 部分。 [Timer] 部分定义了何时以及如何激活定时事件。Timers 可以被定义成以下两种类型:
- 实时定时器(亦称“挂钟定时器”)通过日历事件激活(类似于 cronjobs)定时任务。使用 来定义实时定时器。
- 单调定时器即在一个时间点经过一段时间后激活定时任务。所有的单调计时器都遵循如下形式: 。 和 是常用的单调定时器。
要查阅完整的定时器选项,参见 systemd.timer(5)。关于日历事件和时间段的定义参见 。
服务单元
每个 .timer 文件所在目录都得有一个对应的 .service 文件(如 和 )。.timer 文件激活并控制 .service 文件。对应的 .service 文件中不需要包含 [Install] 部分,因为这由 timer 单元接管。必要时可以通过在定时器的 [Timer] 部分指定 选项来控制一个与定时器不同名的服务单元。
示例
通过定时器预定执行的服务文件一般无需任何修改。以下示例将预定执行 ,因此它的定时器应该被命名为 。
单调定时器
定义一个在系统启动 15 分钟后执行,且之后每周都执行一次的定时器:
实时定时器
定义一个每周执行一次(具体来讲,指周一凌晨零点)的定时器。如果上次未执行(比如说系统当时没有开机,这个行为由 定义)就立即执行服务。
/etc/systemd/system/foo.timer
[Unit] Description=Run foo weekly [Timer] OnCalendar=weekly Persistent=true [Install] WantedBy=timers.target
更精确的时间可以通过 参数以下列方式指定: 可以用星号来表示任意值,用逗号分列可能值。以 分隔的两个值指两个值间的连续序列。
这是在每个月的前四天晚上中午 12 点,但仅当这一天是周一和周四时运行的例子:
OnCalendar=Mon,Tue *-*-01..04 12:00:00
在每个月的第一个星期六运行:
OnCalendar=Sat *-*-1..7 18:00:00
如果不需要以星期几来界定,比如说在每天四点运行,请去掉星期项:
OnCalendar=*-*-* 4:00:00
在不同的时间运行一个服务可以以多次指定 的方式表示。在下面的例子中,这个服务在周内的 22:30 和周末的 20:00 运行:
OnCalendar=Mon..Fri 22:30 OnCalendar=Sat,Sun 20:00
更多信息请参阅 。
瞬态 .timer 单元
可以使用 systemd-run 创建一个瞬态 .timer 单元。即可以在不创建服务文件的情况下设置定时运行某个命令。比如说下面的命令可以在 30 秒钟后创建一个文件:
# systemd-run --on-active=30 /bin/touch /tmp/foo
也可以建立指定一个已经存在但没有定义 timer 的服务文件。比如说,下面的命令会在 12 小时 30 分钟后启动名为 的服务:
# systemd-run --on-active="12h 30m" --unit someunit.service
更多信息和例子参见 。
替代 cron
尽管 cron 毋庸置疑是最有名的计划任务管理器,systemd 定时器仍可以作为一个替代品。
优势
使用定时器的最主要的优势在于每个任务都有它自己的 systemd 服务。这样做的好处包括:
- 任务可以简单地独立于他们的定时器启动,简化调试。
- 每个任务可配置运行于特定的环境中(参见 )。
- 任务可以使用 cgroups (简体中文) 特性。
- 任务可以配置依赖于其他 systemd 单元。
- 任务会被记录于 systemd 日志,便于调试。
注意事项
有些可以用 cron 轻易做到的事情仅仅使用 timer 组件会比较难办:
- 创建过程:相比于在 crontab 中只需添加一行任务,使用 systemd 配置计划任务需要创建两个文件并运行好几次 命令。
- 邮件:目前还没有内置与 cron 类似的任务失败时发送邮件的功能。可以在每个服务文件中配置
OnFailure=来实现同样的功能。
另外, 用户定时器默认只会在用户登录时进行。但是,lingering 允许在启动,且用户没有活动登录会话时激活。
- 随机延时:目前没还有内置与 cron 类似的 功能来指定一个数字用于定时器延时执行。(参见 bug report)。 你不想同时执行的服务必须手动设置它们的定时器。
发送邮件
可以配置 systemd 在单元失败时发送电子邮件。Cron 的 会在任务向标准输出或标准错误输出时发送邮件,许多任务只在发生错误时输出。首先需要两个文件:一个用来发送邮件的可执行文件和一个用于启动这个可执行文件的 .service 文件。在本例中,可执行文件只是一个由提供 的包中给出的调用 的shell 脚本:
不论你用什么可执行文件,应该都会像这个脚本一样接收至少两个参数:目标邮箱地址和用来获取状态的单元文件名。我们创建的 .service 文件会传递这些参数:
其中, 是被通知的用户名,address 是该用户的邮件地址。尽管这个地址被硬编码在代码里,但是报告的单元文件会在实例参数中指定,因此可以作为许多其他单元的邮件服务端。此时你可以 start 服务来检查你能否收信。
成功后,仅需 编辑 你需要发送失败邮件的服务,向 部分添加 。 会向模板传递单元的名字。
- 如果你根据 sSMTP#Security 配置了 sSMTP 安全,
nobody用户会没有访问/etc/ssmtp/ssmtp.conf文件的权限,systemctl start status_email_user@dbus.service命令就会失败。一个解决办法是使用root作为status_email_user@.service单元的执行者。 - 如果你希望在你的邮件脚本中使用
mail -s somelogs address,mail会以 fork 的形式启动,systemd 会把在你的脚本退出时一并将这个进程结束掉。可以用mail -Ssendwait -s somelogs address来让 mail 不以 fork 的形式启动。
参见
- systemd.timer(5)
- Fedora Project wiki page systemd 的实时定时器
- Gentoo wiki section on systemd timer services
- Systemd Timers for Scheduling Tasks