Latest / Linux Server Admin with Fexingo: Sysadmin, Bash, and Server Engineering / How to Use Linux Server Systemd Timer Units for Scheduling
Transcript
- Lucas: So you've been using cron for years — it works, it's reliable, but there's a better way to schedule tasks on modern Linux servers, and it's built right into systemd. Luna: Timer units. I've been meaning to dig into those. Everyone says they're the future, but I still default to cron out of habit. Lucas: Exactly. And look, I get it — cron has been around since the 70s. But systemd timers give you tighter integration with your services, better logging, and more flexible scheduling. Today let's build one from scratch. Luna: If today's tech conversation gives you something usable, consider supporting the show — it keeps us ad-free and focused on real examples. That's buy me a coffee dot com slash fexingo. Lucas: Appreciate that. So let's set the scene: you have an Ubuntu 24.04 server running Nginx, and you want to rotate and archive access logs every morning at 3 AM. Classic cron job, right? Luna: Right, I'd normally write a crontab entry like '0 3 * /usr/local/bin/rotate-logs.sh'. But with systemd, you need two files: a service unit and a timer unit. Lucas: Exactly. The service unit defines what to run. The timer unit defines when to run it. Let me lay out the service unit first. I'll call it 'nginx log archive.service'. Lucas: Inside that file, you put a simple section with a description, then a section that specifies the ExecStart path to your script. Type is oneshot because it runs once and exits. Luna: Oneshot — that's key. If you left it at simple, systemd might think the process is still running. So the service unit is dead simple. What about the timer? Lucas: The timer unit, say 'nginx log archive.timer', has a section that describes it and a section where you set OnCalendar=daily. That's shorthand for midnight, but you can be more precise. Luna: So 'OnCalendar=-* 03:00:00' gives you every day at 3 AM. And there's also OnCalendar=weekly, monthly, or custom like 'Mon..Fri 09:00:00'. Lucas: Right. But systemd timers go beyond calendar events. You can use monotonic timers like OnBootSec=10min, which runs ten minutes after boot — great for startup tasks. Luna: Or OnUnitActiveSec=1h — that re-runs one hour after the last activation. That's something cron can't do without external state tracking. Lucas: Exactly. So after creating both unit files in /etc/systemd/system, you run 'systemctl daemon-reload', then 'systemctl enable nginx log archive.timer', then 'systemctl start nginx log archive.timer'. Luna: Then 'systemctl list-timers' shows you all active timers, the next fire time, and which service they trigger. That's way more visibility than crontab -l. Lucas: And if something fails, you check 'journalctl -u nginx log archive.service' for the output. With cron, you'd have to set up MAILTO or redirect output manually. Luna: So let's say I want to test the timer without waiting until 3 AM. Can I trigger it manually? Lucas: Yeah, 'systemctl start nginx log archive.service' runs the service immediately. The timer still tracks its own schedule independently — it doesn't reset the next fire time unless you use --user mode with special options. Luna: Got it. One thing I've wondered: what happens if the system was off at 3 AM? Does the timer catch up? Lucas: By default, no. If the timer was supposed to fire while the system was down, it skips it. But you can add Persistent=true in the section, and then it'll run as soon as the system boots up. Luna: That's huge for backup jobs on laptops that get suspended. Persistent=true ensures you don't miss a day. Lucas: Exactly. And there's another neat feature: accuracy. You can set AccuracySec=1us for sub-millisecond precision if you need it. But the default is 1 minute, which is fine for most admin tasks. Luna: Wait — cron's granularity is one minute, right? So systemd timers can be more precise if needed? Lucas: Yes, down to the microsecond. But for log rotation, one minute accuracy is plenty. The real win is the integration: you can set dependencies between timers and services using standard systemd directives. Luna: For example, you could require that a database service is running before the backup timer fires, using Requires= or After= in the timer unit. Lucas: Right. And you can even set a randomized delay with RandomizedDelaySec= so that multiple servers don't all hit the same NFS share at once. cron can't do that without a wrapper script. Luna: Alright, I'm convinced. But let's talk migration. I have dozens of cron jobs. Should I rewrite them all? Lucas: I'd say start with the ones that would benefit most from logging and dependency management — backup scripts, maintenance tasks, anything that touches a service. Leave the simple 'run this every five minutes' if it works. Luna: Fair. And you can keep cron and systemd timers on the same system — they don't conflict. Lucas: No conflict at all. I've run both in production for years. The key is to pick one per task so you don't double-fire. Luna: So to recap: create a.service file for the actual command, a.timer file for the schedule, enable and start the timer, and check with list-timers. Persistent for missed runs, RandomizedDelay for load spreading. Lucas: That's the gist. One more thing — you can use systemd-analyze calendar to test your calendar expression. For example, 'systemd-analyze calendar daily' prints the next five fire times. Luna: That's a great debugging tool. I'll definitely use that. So next time I reach for crontab -e, I'll think twice. Lucas: That's the goal. Systemd timers are one of those features that once you start using, you wonder why you didn't switch sooner.