That is not a fair summarization of their point because that is not the grammar. There's commas, slashes, asterisks, combinations, and then if you want randomization you need to put it in the command itself because cron can't do it. (Some crons can, but it's not a general capability of cron.) Writing a non-trivial cron spec is not easy.
This is generally my only real complaint about systemd. I don't care if it is too monolitic, written in C or whatever, I just want a straightforward syntax for straightforward operations. I'd like it if systemd could recognize if a .target file is a shell script and just do "the right thing". Perhaps it would make sense for a timer file to recognize cron syntax as well. Or at least allow for a kind of extensibility so that I can have it supported.
If systemd had a little more respect for existing conventions, I am pretty sure it wouldn't be so controversial. After all, system administrators like it because they use it all the time, but a regular, full-timer user like me, who only deals with it when something is broken or have to use it as a means-to-an-end to set something up, then all friction is annoying and bad UX. (And no, using Nix is not the solution)
$ sudo systemctl edit --force --full my-scheduled-work@.timer
or $ systemctl edit --user --force --full my-scheduled-work@.timer $ systemctl cat public-inbox-watch@.timer
# /etc/systemd/system/public-inbox-watch@.timer
[Unit]
Description=Periodic fetch of public mailing list
[Timer]
# twice a day
OnCalendar=*-*-* 5,17:35
RandomizedDelaySec=1h
Persistent=true
[Install]
WantedBy=multi-user.targetJust use Cron. It does one thing and does it well.
OnCalendar=00/6
You can test it with: systemd-analyze calendar --iterations=6 '0/6:00:00'
The format is `DayOfWeek Year-Month-Day Hour:Minute:Second`https://www.freedesktop.org/software/systemd/man/latest/syst...
Mon,Fri *-01/2-01,03 *:30:45
Who'd ever want to go back crontab format for nontrivial scheduling? [1][0] <https://www.freedesktop.org/software/systemd/man/latest/syst...>
[1] This question is sarcasm. SystemD is often like this... dead simple things look dead simple, but complex things are -if they're possible at all- at least as complex as they are everywhere else.
Looking at the other examples on that page, I'm gonna say that it's only arguably easier to read for basic stuff... especially if you're familiar with the syntax. The complex stuff is -at best- just as difficult.
In cron, you basically have to either use your configuration management to generate those times, or have a random delay script running before the command
In systemd timers, it's just
OnCalendar=0/6:00:00
RandomizedOffsetSec=60m
and the offset generated will be stable for the job on a given machine (i.e. always same on this machine but different on others) so you will get nice uniform distribution of load.If you add
Persist=true
the job will also be run once if there was one or more scheduled runs when the machine was downNope. From crontab(5)
The RANDOM_DELAY variable allows delaying job startups by random amount
of minutes with upper limit specified by the variable. The random scal‐
ing factor is determined during the cron daemon startup so it remains
constant for the whole run time of the daemon.
That's from my cronie install, but it looks like this has been a feature of some crons for at least a decade. (Notice that the post date of [0] is in 2016.) Given that cronie is based on vixie-cron, and I think I was was using vixie-cron in 2002, I bet it's been a thing for at least twenty years.When someone inputs something ridiculous like "5,3/4 4-8,11 1 4,5,6,9-11 */2" you get to enjoy the fun of reverse engineering what they meant (it's never what they actually wrote).
And that's before you get to all the extensions supported in some cron environments (but not all).
I find systemd timers a lot more manageable. Things like having control over whether or not long-running jobs are allowed to overlap and the ability to run tasks between start-finish rather than a fixed time window are major improvements for me. At some point my VPS went down because the backup job ran into some kind of symlink loop and cron just kept spawning more and more backup tasks even though none of them finished.
Having to re-write commands and scripts because CRON had its own special PATH was also a pain point, but the same can be true for some types of systemd timers. But: you can execute those timers manually if you want instead of updating the crontab to trigger in 30 seconds and simply waiting.
Is your example (which I agree, looks cryptic) any less cryptic in systemd?
I asked jippity, and it said this:
[Timer]
OnCalendar=*-04,05,06,09,10,11-01 04..08,11:03/4,05:00
OnCalendar=Sun,Tue,Thu,Sat *-04,05,06,09,10,11-* 04..08,11:03/4,05:00
To which I have to go: "what?"> Things like having control over whether or not long-running jobs are allowed to overlap
With cron that's just prefixing the command with `flock -n <lock>`, but sure the "pick somewhere to put the lock" is probably better with systemd.
> Having to re-write commands and scripts because CRON had its own special PATH
Why? Wouldn't you just put that in the crontab? I don't even see this as different. It's in the cron config or the systemd timer config.
The other improvements you mentioned seem good.
# Run if at least a day has passed since the last run
# and it isn't the weekend.
def should_run(finished, timestamp, dow, **_):
return dow not in [0, 6] and timestamp - finished >= one_day
This was inspired by GNU mcron. In mcron, jobs can calculate the next time they should run using Guile (https://www.gnu.org/software/mcron/manual/mcron.html#Guile-S...): (job
'(next-minute-from
(next-hour (range 0 24 2))
'(15))
"my-program")
I found mcron's scheduling counterintuitive and decided I wanted a function that returned a boolean. I can tentatively recommend it.What's so hard about "At 5 minutes past the hour and every 4 minutes, starting at 3 minutes past the hour, at 04:00 AM through 08:59 AM and 11:00 AM, on day 1 of the month, every 2 days of the week, only in April, May, June, and September through November"?
(I used https://crontab.cronhub.io/ to decode it, to be fair)
That does require you to still know what the default environment is, but it is a mostly completely clean environment, without any influence from any shell.
I'd have to concur that I agree this is an advantage of systemd.
Odd. This script
#!/bin/bash
set > /tmp/set.txt
when scheduled like so * * * * * $HOME/bin/testCronScript.sh
Produces this file in /tmp/set.txt which has had a handful of values (HOME, UID, etc) lightly redacted prior to posting here -to remove PII or for length- but its keys are entirely untouched: BASH=/bin/bash
BASHOPTS=<redacted because long>
BASH_ALIASES=()
BASH_ARGC=()
BASH_ARGV=()
BASH_CMDS=()
BASH_LINENO=([0]="0")
BASH_LOADABLES_PATH=/usr/local/lib64/bash:/usr/lib64/bash
BASH_SOURCE=([0]="/home/user/bin/testCronScript.sh")
BASH_VERSINFO=<redacted bash 5.3.x>
BASH_VERSION=<redacted bash 5.3.x>
DIRSTACK=()
EUID=13370
GROUPS=()
HOME=/home/user
HOSTNAME=hostname
HOSTTYPE=x86_64
IFS=$' \t\n'
LANG=en_US.utf8
LOGNAME=user
MACHTYPE=x86_64-pc-linux-gnu
OPTERR=1
OPTIND=1
OSTYPE=linux-gnu
PATH=/usr/bin:/bin:/usr/sbin:/sbin
PPID=1337
PS4='+ '
PWD=/home/user
SHELL=/bin/sh
SHELLOPTS=braceexpand:hashall:interactive-comments
SHLVL=1
TERM=dumb
UID=13370
USER=user
_=/home/user/bin/testCronScript.sh
Seems pretty clean to me. Even when I run this via /etc/crontab, rather than as a user cron job: * * * * * root /home/user/bin/testCronScript.sh
I get effectively the same results.Maybe your distro's default cron environment was bad, and you never bothered to check and unset the badness? I'd be surprised if they were unable to make the default environment for Timer Units to be bad.
Same here.
We are now considered old and therefore irrelevant. The new generation uses timers and couldn't care less about cron that has served us just fine for decades.
I use cron and my general attitude towards LP and systemd is very similar to the attitude of LP and systemd to us.
That's true, but most people don't know the numbered manual sections, so they get the docs for the cron table command not the cron table config file.
No `man man`? ;)
another benefit is having logs in one place for the job; cron's "send a mail when there is any amount of output text" is just annoying behaviour, but also only place to get the job output unless you redirect it somewhere. Also starting from timer vs just doing systemctl start job.service is the same so easier to debug
other than that the few improvements in how to specify run time have been pretty useful.
For example, setting timer as "persistent" will mean any run "lost" to machine powered off will just be ran next time after boot, so you can have job on your PC that is just "run backup at 2AM" and if you turn it off before that you get the backup done first thing in the morning
There is also both random, and fixed (depending on machine UUID) random delay so avoiding thundering herd problem with backups is also pretty convenient.
There is even option to wake a device for the job if necessary tho the problem of shutdown is left to the user. And picking whether to start counting to next timer from previous one or from the job's end.
What I would like also is to have job summary page ("hey this job was done X times but failed Y times") but that's probably better left to external tooling
> You can set the PATH right in the crontab. Is that harder to "predict" than it being set in /etc/bashrc, ~/.bashrc, ~/.profile, ~/.bash_profile, /etc/systemd/…, or wherever else?
There is* a common trap as the cron PATH is usually just /usr/bin:/bin so anything in /usr/local/bin, or in /sbin won't be there.