IT Practice Exams

XK0-006 · Services and User Management · Updated July 26, 2026

systemd Timers vs Cron: Scheduling Jobs on Modern Linux

Linux gives you two mainstream ways to run jobs on a schedule: cron, the classic daemon driven by crontab files, and systemd timers, which schedule the activation of service units. A systemd timer is a .timer unit that, when it fires, starts a matching .service unit — the timer holds the schedule, the service holds the work. Cron is simpler and universal; timers give you logging in the journal, dependency handling, catch-up runs for machines that were powered off, and fine-grained control directives. XK0-006 expects you to operate both and to know exactly how the pieces of each fit together.

How cron works

The cron daemon (crond or cron) wakes every minute and runs anything due. Schedules live in crontabs:

  • Per-user crontabs, edited with crontab -e (list with crontab -l, remove with crontab -r). Five time fields, then the command: minute, hour, day-of-month, month, day-of-week.
  • The system crontab, /etc/crontab, plus drop-ins in /etc/cron.d/. These have a sixth field — the user to run as — inserted between the time fields and the command.
# m  h  dom mon dow user  command
 17 *   *   *   *  root   cd / && run-parts --report /etc/cron.hourly

That line reveals a detail the exam loves: the scripts you drop into /etc/cron.hourly, /etc/cron.daily, /etc/cron.weekly, and /etc/cron.monthly are not read by cron directly. The system crontab schedules a single entry per directory, and that entry invokes run-parts, a helper that executes every executable script in the named directory. So when you’re asked what actually runs the scripts inside /etc/cron.daily, the answer is run-parts (often via anacron on distributions that install it), not the cron daemon iterating the directory itself.

Cron’s blind spot: if the machine is off at the scheduled moment, the run is simply skipped. anacron exists to patch that for the daily/weekly/monthly directories — it tracks timestamps and runs overdue jobs after boot — but classic per-minute cron entries get no such recovery.

How systemd timers work

A timer is always a pair of units sharing a base name:

  • backup.timer — contains a [Timer] section defining when to fire.
  • backup.service — the actual job (usually Type=oneshot with an ExecStart=).

By default a timer activates the service with its own name; you only need Unit= in [Timer] if the names differ. This pairing is the number-one operational gotcha: a timer can be enabled, active, and show a perfectly valid schedule, yet nothing ever happens at the appointed time — because the matching .service unit was never created (or is misnamed). The timer fired into a void. Always confirm both halves exist.

A minimal pair:

# /etc/systemd/system/backup.timer
[Unit]
Description=Nightly backup schedule

[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true

[Install]
WantedBy=timers.target
# /etc/systemd/system/backup.service
[Unit]
Description=Nightly backup job

[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh

Enable and start the timer, not the service: sudo systemctl enable --now backup.timer. Inspect schedules with systemctl list-timers (shows next and last trigger per timer) and validate calendar expressions with systemd-analyze calendar "Mon *-*-* 09:00". For the anatomy of the [Unit]/[Install] sections themselves, see systemd unit files.

The [Timer] directives that matter

Legitimate [Timer] section directives — the exam likes to hide fakes among these:

  • OnCalendar= — real-time (wall-clock) schedule, e.g. OnCalendar=weekly or OnCalendar=*-*-01 04:00:00.
  • OnBootSec= — fire a set time after boot (monotonic).
  • OnStartupSec= — a set time after the systemd manager started.
  • OnActiveSec= — a set time after the timer itself was activated.
  • OnUnitActiveSec= / OnUnitInactiveSec= — relative to when the triggered unit last started / last finished; the standard way to build “every N hours” repeating jobs.
  • Persistent=true — with OnCalendar=, records the last trigger time on disk; if the machine was off when the schedule came due, the job runs as soon as possible after the next boot. This is the fix for a laptop that keeps missing its weekly maintenance window overnight.
  • RandomizedDelaySec= — adds random jitter so fleets don’t all fire at once.
  • AccuracySec= — how much systemd may coalesce/delay the trigger to batch wakeups (default is one minute, which surprises people expecting to-the-second firing).
  • Unit= — explicitly name the unit to activate when it differs from the timer’s base name.

Directives like WantedBy= or ExecStart= belong to [Install] and [Service] respectively — appearing in a [Timer] answer choice, they’re distractors.

Choosing between them

Cronsystemd timers
Job definitionOne crontab line.timer + .service unit pair
Schedule syntax5 fields (m h dom mon dow)OnCalendar= calendar expressions + monotonic On*Sec=
Missed runs (machine off)Skipped (anacron only covers cron.daily/weekly/monthly)Persistent=true catches up at next boot
Output/loggingEmailed to the user (if an MTA exists) or lostCaptured in the journal per service
Dependencies/resourcesNoneFull unit machinery: After=, resource limits, sandboxing
Randomized spreadNot built inRandomizedDelaySec=
Ad-hoc one-shotat commandsystemd-run --on-active=30m ...

Cron remains fine for a quick one-liner under an unprivileged user. For system maintenance on a systemd distribution — anything needing logs, ordering after network or mounts, or catch-up behavior — timers are the modern default, and most distributions have already migrated their own maintenance jobs to them — the daily updatedb index rebuild is a typical example.

How the XK0-006 exam tests this

  • A timer is enabled and active with verified-correct OnCalendar= syntax, yet the job never executes — the expected diagnosis is the missing (or misnamed) companion .service unit.
  • A machine that’s regularly powered off keeps missing a calendar-scheduled job; the answer is adding Persistent=true so the run fires after the next boot.
  • A “which of these are valid [Timer] directives” multi-select mixing real ones (OnCalendar=, OnBootSec=, OnUnitActiveSec=) with directives lifted from [Service] or [Install].
  • A plumbing question on the /etc/cron.* directories: recognizing that run-parts, invoked from the system crontab, is what executes the scripts inside them.

Scheduling questions fall in the Services and User Management domain — see the full XK0-006 study guide for the complete exam map. Timer directives are pure recall — drill it with practice questions until OnCalendar= syntax is automatic.

Quick reference

  • systemd scheduling = a .timer unit (the schedule) triggering a same-named .service unit (the work); no service, no job.
  • Enable the timer, not the service: systemctl enable --now name.timer; audit with systemctl list-timers.
  • OnCalendar= is wall-clock; OnBootSec=/OnActiveSec=/OnUnitActiveSec= are monotonic intervals.
  • Persistent=true replays a missed OnCalendar= trigger after boot — cron has no per-entry equivalent.
  • Test schedule strings with systemd-analyze calendar.
  • User crontabs: 5 time fields + command; /etc/crontab and /etc/cron.d/: extra user field before the command.
  • Scripts in /etc/cron.daily and friends are executed by run-parts (with anacron providing catch-up on many distros).
  • Timer job output lands in the journal — read it with journalctl -u backup.service.
Choose your exam → Lifetime access
from $59, once