你不够喜爱 Systemd 定时器。
You Don't Love Systemd Timers Enough

原始链接: https://blog.tjll.net/you-dont-love-systemd-timers-enough/

在配置 systemd 定时器时,最关键的区别在于**日历事件**(具体的挂钟时间)与**时间跨度**(相对间隔)之间的不同。 `systemd.time(7)` 手册是理解这些表达式的权威资源。若要验证语法,请使用 `systemd-analyze calendar` 命令,它能校验输入内容并显示下一次执行时间。 虽然 cron 任务仅限于固定的时间表,但 systemd 定时器允许进行更智能的事件驱动型执行。你可以根据系统事件来定义任务,例如 `OnBootSec`(在启动后运行任务)或 `OnUnitActiveSec`(在服务上次运行后的特定时间间隔重复执行任务)。 这种方法通常优于传统的 cron;例如,相对于服务运行时间而不是固定时钟时间来错开任务,有助于避免“惊群效应”,并确保进程在真正需要时运行。掌握基于日历和基于间隔的调度之间的区别,是有效管理 systemd 自动化的关键。

这篇 Hacker News 讨论帖探讨了使用 systemd 定时器进行任务管理的优劣。用户普遍称赞 systemd 是一款强大且标准的 Linux 生命周期管理工具,并指出相比 macOS 的 *launchd* 等替代方案,它往往显得更加原生且强大。 讨论的很大一部分集中在 systemd 配置语法的审美与易用性上。尽管一些用户认为服务文件的格式“丑陋”,但也有人支持这种简洁的 INI 风格结构,认为它比 XML 或 YAML 等格式更易于手动编辑且不复杂。此外,用户强调了使用 NixOS 的好处,它提供了一种更简洁、更具编程风格的方式来定义 systemd 服务。该讨论还涉及了倾向于简单配置文件的用户与主张使用更结构化格式(如 XML)以实现更好验证和图形界面管理的用户之间的分歧。
相关文章

原文

Arguably the most important bit of information about timers is how to express a schedule, whether a repeating period of time (which the manual usually refers to as a time span) versus a calendar event (or a timestamp). Fortunately, I think the man page for this under systemd.time(7) is actually very good with plenty of examples. You should use it as the first resource when writing timers; it's good (or better) than, uh, casual blog posts by casual writers.

systemd also ships with a command-line tool called systemd-analyze which includes the ability to validate and explain time expressions from the command line directly in an imperative way to help understand them. You can even disambiguate the classic wildcard cron expression which systemd-analyzer can parse and then explain to you, complete with the expected execution times:

shell
systemd-analyze calendar '*-*-* *:*:*'
Normalized form: *-*-* *:*:*
    Next elapse: Sat 2026-04-18 16:44:26 MDT
       (in UTC): Sat 2026-04-18 22:44:26 UTC
       From now: 431ms left

This blog post is not the place to reproduce the entirety of systemd.time(7) verbatim, so I encourage you to Read The Helpful Manual (RTHM). Writ small, you can pretty simply define either a recurring wallclock period or, in contrast to plain old cron, a recurring period of time against some previous event.

The first category of time expressions is easy to envision. For example, in fully-qualified form, daily means:

*-*-* 00:00:00
│ │ │ │  │  ╰── at second 00
│ │ │ │  ╰───── at minute 00
│ │ │ ╰──────── at hour 00
│ │ ╰────────── every day
│ ╰──────────── every month
╰────────────── every year

You can use shorthand terms like daily, write out the complete form, or use any other supported value listed out in systemd.time(7) and subsequently validate your assumptions against systemd-analyze.

The second category of time expressions apply to "run this relative to some other event." This distinction from "run at the same time very day" is very often what you actually want. Consider a job that clears out a temporary directory, for example: if a cron expression lapsed right after boot, there probably isn't much to clean out of /tmp at all. But if you encode "execute an hour after my computer has started and then every hour after that", the schedule logic is meaningful for what the related service is actually doing.

This is easy to do in a timer:

Systemd
  • Font used to highlight keywords.
  • Font used to highlight type and class names.
[Timer]
OnBootSec=1h
OnUnitActiveSec=1h

That is: "run an hour after the machine starts" (which will execute once) and also "run one hour after my Unit= runs" (which implicitly makes the timer repeat indefinitely.)

Periodic time spans like this fit the "every once in a while" use case surprisingly more often than "run at this minute every hour" and similar expressions. Another good example is a timer I use every December to poll the Advent of Code API for a Slack bot I wrote for some friends. The */15 cron expression honors the "every 15 minutes" policy that their API requests, but since that's the easiest way to express it in cron language, I'm sure it makes spiky traffic alongside everyone else polling the API! Starting my timer when I've made a code fix that runs whenever 15 minutes has lapsed is all I care about, and probably creates less of a thundering herd problem.

Calendar versus time span units is probably the biggest conceptual leap from a traditional cron job, but timers offer more, too.

联系我们 contact @ memedata.com