I haven't used systemd timers enough to disagree, but
> Ambiguous $PATH settings make cron script execution difficult to predict.
What makes you say that? 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?
> You might feel cool knowing the scheduling grammar by heart
I've used Linux since 1994 and I don't know it by heart. But luckily it's pre-printed in the crontab as comments:
# For more information see the manual pages of crontab(5) and cron(8)
#
# m h dom mon dow command
You just put numbers aligned with the titles.
The rest of the complaints, sure. Next time I need a cronjob, I'll try it out.
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.
I am familiar with the syntax, so I am biased ("*/3" and "12,14,20" makes sense if you are familiar with Unix tools), but it is still more intuitive to me than the systemd unit file syntax and usage. I know that I just have to edit /etc/cron or throw any executable file into /etc/cron.d/monthly and it will work on my system, but I cannot write a systemd timer file from scratch without looking it, and to do that I first have to find the directory where the other examples are located. /etc/systemd doesn't appear to be it.
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)
Systemd lets you create templates that take an argument in from the scheduled service. It gets that from the value after the @. So you can write a unit file that schedules a task to run say every 3 days and in that unit file reference `jobs/%i`, then put your task in a file in jobs and say `systemctl start every-3-days@script1.sh` to run `script1.sh` on your schedule without needing to create a new unit file for each script. StepCA has a nice write up on their site about using these templates to schedule cert renewals for any arbitrary service
Yeah, it would be nice to have a folder like /etc/systemd-jobs/ where I could put them and where there are no files unrelated to job scheduling. There is /etc/systemd/user, but it does get a bit of pollution depending on the system.
Not sure if you're talking about cron or systemd, but cron definitely has that in /etc/cron.d where you can have arbitrary crontabs, or /etc/cron.{hourly|daily|weekly|monthly} where you can just place arbitrary scripts if you don't care exactly when they run, just the frequency.
That's simple but consider "run something 4x per day but randomize a delay by hour so all of the 200 servers doing that task won't run it all at once"
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 down
> 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
Nope. 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.
It's a mystery to me why everyone tries to use OnCalendar here, when "n amount of times within a certain timeframe" can be done much more easily with OnActiveSec, in this case that'd be OnActiveSec=6h.
$ 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.target
1) Your production equipment doesn't have its TZ set to UTC? Enjoy dealing with the intermittent and irregular hassle of DST changes, I guess.
2) From the crontab(5) on my system:
The CRON_TZ variable specifies the time zone specific for the cron ta‐
ble. The user should enter a time according to the specified time zone
into the table. The time used for writing into a log file is taken from
the local time zone, where the daemon is running.
If you have a job you need scheduled in a different timezone, dump a new file in /etc/cron.d, alter its CRON_TZ variable and go to town, as it were.
[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.
I found the systemd time spec syntax you referenced to be logical and well thought out.
Cron syntax is simpler for the easy cases because cron tries to do less. It ignores years and seconds entirely, and doesn't try to adhere roughly to ISO8601 ordering and field separators, instead using space universally for field separation and euro-style least-to-most significant field ordering. I like ISO8601, so I get along with systemd's style better, despite it introducing slightly more cognitive load.
The only thing that threw me for a loop and seems like "special magic" was
> "Mon *-05~07/1" means "the last Monday in May."
But good luck doing that in one line in cron.
Some cron-style libraries seem to support L/W/# for last / nearest-weekday / nth of month, but I don't know if any system crons do. (cronie? dcron? I don't think so. fcron? bcron? I don't see it there either.) '#' is syntactic sugar for DOW + 7-day range, while L is covered by the above quoted syntax.
If your cron has that kind of syntax, then for a case like "weekday closest to 1st of month", "W" is more convenient than writing 3 systemd timer rules to cover the three cases (weekday day 1, monday day 2, friday last day of month), but that's a big if. Generally you'd have to write 3 rules in cron anyway.
> I found the systemd time spec syntax you referenced to be logical and well thought out.
I found this amusing when in combination with
> The only thing that threw me for a loop and seems like "special magic" was
but -regardless- a careful reader notes that I never said that the Timer scheduling syntax was illogical or poorly thought out. It's at least as complicated as crontab-style time syntax, which was my entire point.
Related: Not that it's ether part of the core scheduler syntax or necessarily as nice as having it in the core syntax, but my crontab(5) suggests that one can use things like date(1) to get more fine-grained control over the time of execution:
As noted above, skip values only operate within the time period they´re attached to.
For example, specifying "0/35" for the minute field of a crontab entry won´t cause
that entry to be executed every 35 minutes; instead, it will be executed twice every
hour, at 0 and 35 minutes past.
For more fine-grained control you can do something like this:
* * * * * if [ $(expr \( $(date +%s) / 60 \) % 58) = 0 ]; then echo this runs every 58 minutes; fi
0 * * * * if [ $(expr \( $(date +%s) / 3600 \) % 23) = 0 ]; then echo this runs every 23 hours on the hour; fi
Adjust as needed if your date(1) command does not accept "+%s" as the format string
specifier to output the current UNIX timestamp.
While I expect that you're not one of those people, I know that folks who are accustomed to working with extremely inflexible tools forget (or never learned) that these sorts of things are possible. I'm very aware that people sometimes cut off their own limbs with power tools, but that's not a good reason to ban their use.
Obviously you can do additional time & date checking in a shell wrapping the script or binary cron ultimately runs, just as you could do the time & date checking in the script or binary itself. That's far more complex.
Systemd enables cleaner, simpler syntax for common cases. Instead of "59 23 * * *", simply "23:59". Instead of "0 0 * * sun[day]", simply "sun[day]". 1st of the month and don't care exactly what time? Instead of "0 0 01 * *", simply "*-*-01".
Systemd started with the principle that they wanted to accept ISO8601 timestamps, then extended that with lists, increments, ranges. They developed that into a superset of basic cron capabilities, while maintaining similar syntax as best they could for increments and lists; they diverged for ranges and nth-from-last because those conflicted with the - date separator. They repurposed the little-used ~ cron randomization operator in the process. (systemd uses a separate RandomizedDelaySec line for that, which is also arguably superior because it randomizes per trigger, not on initial load of the timer)
The alternative is how AWS does it. They have separate cron() and at() syntax. at() takes timestamps. cron() takes cron+quartz syntax, mangled to remove seconds. They also have rate(value units), because apparently cron syntax is too complicated for most people. I'm sure in theory they did it to support "every 7 minutes" cases. I bet if you surveyed actual rate() AWS schedules, 99% would be cases that evenly divide a larger time unit, and could therefore be implemented with cron().
Cron syntax is more of a mess than I thought. While basic system crons don't support any advanced features, AWS and Cloudflare have adopted LW# capabilities, derived from quartz job scheduler syntax (Cloudflare references quartz explicitly). Quartz has extra fields for seconds and year (year optional, so it must go last, which breaks d m Y sequencing) so its syntax has 6 or 7 fields vs the standard 5. CF uses 5 fields, no seconds or years. AWS uses 6 fields, years but not seconds. Whenever you interact with cron-derived systems, you have to remember not just whether they support quartz-style syntax, but whether they support seconds and/or years. Is that really simpler?
The one feature I found interesting, "W", may not work the way I anticipated according to quartz's documentation. I thought "nearest weekday to the 1st of the month" might be useful because it maps to some billing cycles, but quartz (at least through 2.3) couldn't do that. The 2.3 docs say that 1W, if the 1st falls on a Saturday, triggers on the 3rd because it won't jump backwards over a month boundary. That was my only interesting use case for "W". Systemd does everything else, though it requires more verbosity in some cases, it's simpler in many others. 2.4/2.5 are from the last couple of years, and their docs are restructured and don't mention that, so maybe it was finally fixed? I'm not about to install java crud to test.
I didn't find the *-*~01 syntax that strange (last day of every month). The "fri *-*~07/1" syntax for "last friday of every month" is what I found magical, but it makes sense now that I've thought about it more.
What would you prefer for 3rd friday of the month? Cron (5-field, quartz syntax)
0 0 ? * fri#3 (special syntax is needed because cron uses logical-or to combine day and weekday fields)
or systemd
fri *-*-15..21 (works because systemd day and weekday are joined with logical-and)
> Systemd enables cleaner, simpler syntax for common cases.
I disagree. It's all a matter what you're accustomed to. On top of that, what's at least as important as clear syntax for simple cases is the establishing of a handful of rules that well serve both the simple and complex cases. Consistency that leads to complicated cases being made easy should not be avoided just to make the simple cases extremely welcoming to the newcomer. Note that I'm not saying that 'systemd-crond' falls into this trap, but I am saying that oh so many tools that aim to be "approachable by newcomers" enthusiastically throw themselves into it.
> Cron syntax is more of a mess than I thought.
Nah. It's just there are a very large number of cron implementations. If The Systemd Project were actually a thing that people could make an independent reimplementation of, we'd see at least as much inconsistency in 'systemd-cron' scheduling syntax as people extended it in their reimplementations to meet their needs.
> What would you prefer for 3rd friday of the month? Cron (5-field, quartz syntax)
I don't understand why the "day of month" column has a "?" instead of a "*", and I don't understand why "fri#3" isn't rendered as "Fri/3", but whatevz. I prefer that to the systemd syntax.
FWIW, I think you can directly translate your systemd scheduler line into this for most crons:
* * 15-21 * Fri
Edit: Oh, no, you cannot. From crontab(5)
Note: The day of a command’s execution can be specified in the following two fields — ’day of month’, and ’day of week’. If both
fields are restricted (i.e., do not contain the "*" character), the command will be run when either field matches the current time.
For example,
"30 4 1,15 * 5" would cause a command to be run at 4:30 am on the 1st and 15th of each month, plus every Friday.
Hm... Yeah, the handling of the "day of week" column is a terrible wart on the rules.
I think you're talking about syntactic simplicity. Systemd requires three field separators (space, :, -) because that's how ISO8601 dates are written. That means not all fields will be space separated, which may be more challenging to visually parse. It's not going to look as clean. Is that what you mean?
Everything else is simpler. You don't have to count fields to figure out whether you're dealing with a day vs a month, or an hour vs minute, no matter how the fields are aligned or how long or complex they are. You can scan left and right and look for space and dash and colon to figure out where you are. The formats for time and date are distinctive and ubiquitous. You don't have to guess what you're looking at when you just see one of them in isolation.
Very little follows from cron's format. You have to learn which fields are which for your particular implementation: does it include seconds? You have to learn the bizarre interaction between day and weekday, to do something non-trivial with them. You have to carefully keep track of which field you're in because you can't determine that from neighboring syntax. The visual clutter, if you want to call it that, of systemd's iso8601-based syntax only applies if you're doing complicated rules. In the vast majority of cases it would simply be an ISO8601 timestamp with various values replaced with *'s, and at most one /.
That first impression you had is what I thought too, before diving into it for my previous replies. But no, cron logic is that day and weekday are ORed. It lets you do clever things like run a script on the 1st and 15th of every month, AND on mondays, all in one line. I don't think I've ever seen such a thing in the wild. I'd go so far as to say it's stupid, because it's likely to be misinterpreted if anyone did use it that way. All the other fields are ANDed. I would say that systemd's AND logic is better... and more consistent, which is your own acceptance criterion.
> It's not going to look as clean. Is that what you mean?
Nope. I don't give a shit how "clean" something looks, [0] I just care how difficult it is to learn and either retain or remind yourself of the syntax when you need to do something complex with it. In that regard, [1] systemd-crond's scheduler syntax is at least as complicated as that of most crons'.
> You don't have to count fields to figure out whether you're dealing with a day vs a month, or an hour vs minute, no matter how the fields are aligned or how long or complex they are. You can scan left and right and look for space and dash and colon to figure out where you are.
So, you have to learn a tool-specific format. Just like you do for crontab. I've read both man pages, and I'm 100% unconvinced that systemd-crond's scheduler syntax is actually simpler. I do agree that it can express specific schedules that one cannot in the syntaxes used by most cron implementations.
> Very little follows from cron's format. You have to learn which fields are which for your particular implementation:
Sure. And I expect that exactly nothing other than systemd-crond uses its weirdo syntax. And -as I mentioned in the comment you're replying to-
Nah. It's just there are a very large number of cron implementations. If The Systemd Project were actually a thing that people could make an independent reimplementation of, we'd see at least as much inconsistency in 'systemd-cron' scheduling syntax as people extended it in their reimplementations to meet their needs.
> But no, cron logic is that day and weekday are ORed. It lets you do clever things like run a script on the 1st and 15th of every month, AND on mondays, all in one line. I don't think I've ever seen such a thing in the wild. I'd go so far as to say it's stupid...
On this I agree with you. Changing the rules for the Day Of The Week column (but only when it's used in combination with the day of the month column) is catastrophically idiotic. The only time I've ever had need to use the DoW column was to schedule something to run weekly... so I've been blissfully unaware of how incredibly idiotic that behavior is.
[0] If anything, I've noticed a strong inverse correlation between how "clean" a syntax is regarded to be and how easy it is to both do complicated things with it, and come back to those complicated pieces of work six+ months later and be able to understand what the hell you did.
[1] With the notable exception of cron's DoW column.... read on for further discussion.
The first one works in that specific case, but not more generically. For example, "Last Monday in February", or "last Monday of the month" for multiple months unless they're all 30 or all 31 days.
This was fun to cook up and may (or may not!) break if one's locale changes:
# Run a command on the last day of the month. Only starts checking at midnight towards the end of the month. Assumes GNU date, which is fair if we're discussing a Linux-only cron-alike.
0 0 28-31 * * if [ $(date +\%d) -eq $(date --date="$(date +\%m)/1 + 1 month - 1 day" +\%d) ]; then /usr/local/bin/runCommand.sh; fi
I bet one could do something similar to determine if we're at the "last $NAMED_WEEKDAY in the month" by counting ahead a week and seeing if the month name changes.
If I were doing this for real, I'd either switch to a more capable cron, or take a serious try at the date math and then wrap it up as a standalone helper. Or I guess I'd look to see if someone already built that helper. ...I guess...
I am curious whether there's a more capable system cron that supports that kind of thing. Quartz job scheduler (java), AWS, and CF obviously wouldn't qualify. I think this is only possible if you're using a heavyweight job scheduler like those. Or... systemd.
It ultimately doesn't matter "for real", because almost nobody without some horrific legacy system to integrate with would need to use anything more than lists, ranges, and increments. There's a reason nobody's added these features to system crons. Clever trigger times for events that don't really need to be triggered at clever times... sure, but lacking that capability wouldn't change anything, the trigger would just be a more boring one.
Events like "last Friday of the month" or "nearest weekday to the 1st of the month" or even "Friday the 13th" are more for business logic, not system crontabs.
> I am curious whether there's a more capable system cron that supports that kind of thing.
I am no cron scholar, nor am I young enough to have the energy required to do an exhaustive survey... so -sadly- I don't know of one. It seems like there'd be one being used internally in at least one business in the world, though, yanno? That just seems like the sort of thing that at least one bored programmer would take a few days to crank out.
> Events like "last Friday of the month" or "nearest weekday to the 1st of the month" or even "Friday the 13th" are more for business logic, not system crontabs.
Oh quite possibly, yeah. But, system crons are quite fine for one-shot things that are re-run on a regular schedule... as well as things that don't have complicated scheduling and/or retry requirements. If you're working on a Big Enterprise Project [0], then you're almost certainly going to have a scheduler inside of you, and -IME- you're very likely to use it to do a lot of that BEP's scheduled tasks. [1]
[0] Or a tiny one wearing the clothes of a BEP
[1] ...if for no other reason than it requires little effort to get the BEP's data and code into its internal scheduler, and can be a huge pain in the ass to get it into an external one.
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.
Having had to work on an application supposedly supporting cron expressions: the numbers are just the basic parts of the language.
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.
This is like a complaint about regex syntax. It's impossible to comprehend a non-trivial regex in a second or two. However, if you know the rules, it's trivial to step through it. What's the point of complaining? There's no representation that anyone could grok on first impression. This is much simpler than regex.
Nobody's prevented from using cron instead of systemd timers. The significant differences in typical relatively simple cases are ordering:
cron: M H d m Y DOW
systemd: DOW Y-m-d H:M:S [each part optional, with *, *, and 00:00:00 defaults]
And then, because - is taken, ranges use .. in systemd. Aside from that, it's mostly the same for typical cases of simple periodic timers. Even x/n and x-y/n for steps work similarly. Syntax for complex cases start to diverge, for jitter or special numerically-irregular DOW or DOM or multiple non-periodic times.
In your example, adding more spaces between the date and time parts would make it more visually digestible. There's also the .. range operator which jippity strangely didn't use for the month field even though it did for the hours field.
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"?
Complex expressions are one of the things I don't like in cron. On Debian/Ubuntu servers, I just bite the bullet with systemd timers. On my workstation, I have a personal job scheduler that feels easier and more fun to tinker with. The scheduler uses Starlark functions instead. For example:
# 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
> What makes you say that? You can set the PATH right in the crontab.
OK but I don't want to hardcode $PATH in the crontab just so I can test the cronjob.
Barring the hardcode, $PATH is one thing when cron runs and another when you try out the command yourself. systemctl start foo.service starts the command inside with the same environment as when the timer fires so you know it'll work the same.
On the flip side, your cron job will run at the time you specify in the crontab. Your systemd timer, on the other hand, may fire at the specified time (and most of the time, it will), but it can also suddenly stop firing once it has fired on a February 29th and then never fire again, due to logic bugs in systemd, or it may or may not fire when you "restart" the timer unit, due to logic bugs in systemd (that's when it only has OnCalendar, so yes, definitely a bug).
> $PATH is one thing when cron runs and another when you try out the command yourself.
Why would that be different with systemd timers? If my ~/.bashrc adds /opt/foo/bin, that's also not part of the systemd timer's PATH, right?
But I guess you're saying the ability to trigger the systemd timer off-schedule is the difference? Yeah, it's annoying with cron to have to temporarily set the trigger two minutes into the future. :-P
Not sure adding that feature justifies a complete rewrite, but certainly a nice addition.
> due to logic bugs in systemd
Yeah my main gripe with systemd and other Lennartware is the extremely low implementation quality, not necessarily the ideas. Though the idea of killing tmux/screen on logout is downright criminal. And the fd passing nonsense[1] for system services is clearly just the idea of a child that found a tool and is misusing it.
>But I guess you're saying the ability to trigger the systemd timer off-schedule is the difference? Yeah, it's annoying with cron to have to temporarily set the trigger two minutes into the future. :-P
>Not sure adding that feature justifies a complete rewrite, but certainly a nice addition.
If there is a feature that justifies using a completely different tool it's obviously this one.
> Because you can test if systemctl start foo.service works and if it does, you know it'll work when foo.timer triggers it.
It's a better workflow than the one I mentioned for cron, yes, but it's nothing inherent. I would not call the difference one of being "predictable", though.
The article and thread is full of complaints about cron that are either just missing features that could be added (like this one, trigger on demand), exactly the same ("the time spec is too complex"), or just plain "no you can already do that with cron".
> How is this different? Any way you slice it, you have to configure it somewhere if you're not lucky enough for the default to be acceptable.
It's a workaround for a design flaw. If you forget it you'll notice when it fails in production. There should rarely be a need to change the default path (just specify the full path if necessary), it should just be the same when you test and when it runs by itself. Trigger on demand would of course solve that.
> exactly the same ("the time spec is too complex")
Of course, the timespec complaint is bullshit. Both have manpages that will tell you immediately if you don't have it memorized.
That's what I'm saying though; how is it a design flaw? It's arguably a flaw in the default configuration. That's certainly fixable without changing the design at all.
> Trigger on demand would of course solve that.
Is it a design flaw that you can't trigger the job as a test? No, that's just a missing feature.
The main nice thing about the environment in systemd is that it is standard and mostly a blank slate, whereas at least for me I was always getting bit by the fact that the environment in Crontab was completely different from say, the environment inherited by supervisord or sysvinit scripts. In systemd the actual unit that gets executed is the same regardless of what triggers it, so there is no gap.
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.
> 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.
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:
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.
Regardless of exactly how clean the environment is, my favorite part of systemd is the fact that there is only one regardless of how something was triggered. Whether a unit is triggered via a mount unit, timer unit, udev rule, it's the same units at the end, so it's the same environment.
The same problems that could be caused by a polluted environment in cron can be caused in reverse by a polluted environment elsewhere, when you unwittingly copy a command that depends on some environment being set. If you are using systemd as the service manager, this necessarily doesn't happen because it's all units. (Well, you could still copy something from outside of systemd and run into a similar problem, but at least there's essentially only one set of caveats you have to learn for whatever thing you want executed in the background.)
So I guess this isn't so much cron vs systemd timers, but more cron + other init and service supervisors vs systemd init in general.
> Regardless of exactly how clean the environment is, my favorite part of systemd is the fact that there is only one regardless of how something was triggered. Whether a unit is triggered via a mount unit, timer unit, udev rule, it's the same units at the end, so it's the same environment.
>
> The same problems that could be caused by a polluted environment in cron can be caused in reverse by a polluted environment elsewhere, when you unwittingly copy a command that depends on some environment being set.
I'm confused about what you need this for? Are you running some utility command that needs the same environment provided by the daemon's service file? If so, any competent init system lets you extend upstream-provided service files. In OpenRC:
So, if you need to do maintenance for a service on a schedule in the same environment that is provided for starting that service, you can simply extend the service script and use cron to execute that functionality.
But. Another thing that confuses me is why you think that SystemD [0] provides anything special here? If you were to create a service file in most any other service manager and start it with cron, you'd get exactly the same environment sanitization as you get for all other services. Given your testimony, I expect that prior to SystemD, you'd have refused to create service files for things like one-off jobs that weren't system services... so why are you okay with it now that you're using SystemD?
[0] I spell it "SystemD" not to mock it -as I understand some do- but to distinguish The Systemd Project from systemd(1). It sucks minor ass that the two share the same name, but what can you do?
I wouldn't say that the PATH is ambiguous, but cron does have some problems with PATH:
- the default value is missing some values you would expect, like /use/local/bin and /usr/sbin for root.
- on some distributions (for example Arch Linux) the man page doesn't even say what the default path is, or recommend setting it.
- if you need to add something to the path for a single script, you either need to wrap it with a call to env, set it in a wrapper script, or set the path before the entry and reset it afterwards
- you can't use ~ or $HOME in the path, you have to write out the full absolute path. Which is particularly annoying for user crontabs.
Sure, it isn't too hard to work around those, but IMO systemd timers are a better experience, especially since the default uses the same path as all your other services.
> - the default value is missing some values you would expect, like /use/local/bin and /usr/sbin for root.
What do you mean by "you would expect", that doesn't also apply to systemd timers? /opt/foo/bin is not in the path. Would you expect that?
And if this is an objective problem, can we just change the cron default PATH?
> - on some distributions (for example Arch Linux) the man page doesn't even say what the default path is, or recommend setting it.
Send a PR. This doesn't seem like an inherent problem.
> - if you need to add something to the path for a single script, you either need to wrap it with a call to env, set it in a wrapper script, or set the path before the entry and reset it afterwards
Or on the line, right?
* * * * * FOO=bar $HOME/bin/foo.sh
The line can get long, but is this really a problem?
> - you can't use ~ or $HOME in the path, you have to write out the full absolute path. Which is particularly annoying for user crontabs.
This is incorrect. You can definitely use $HOME in user crontabs.
I'm still not seeing something that warrants a rewrite. (except what you did not mention, which is the ability to run "trigger this now" as a missing feature)
I mean it should include things that are usually on the path, like /usr/local/bin. And for the root user it should include sbin.
I don't really expect /opt/foo/bin to be there, but if you want to have it available by default everywhere then you can just add it to systemd once, rather than having to remember to add it to crontab as well.
> Or on the line, right?
Oh you're right. I forgot cron evaluates the command with the shell (which has its own set of issues...)
> This is incorrect. You can definitely use $HOME in user crontabs.
You can in the command itself, because that is evaluated by a shell, but not when setting an environment variable. From the Ubuntu crontab(5) manpage:
> The value string is not parsed for environmental substitutions or replacement of variables or tilde(~) expansion
Maybe it depends on the cron implementation though. The cronie documentation doesn't say either way.
> I mean it should include things that are usually on the path, like /usr/local/bin. And for the root user it should include sbin.
So changing the default PATH for cron requires a green field rewrite? You would expect /usr/local/bin. cron doesn't include it. It seems like a disagreement on default settings. I would agree with you about what the default should be, but I don't understand how this has anything to do with cron either as code or architecture.
This seems a bit like /sbin being missing in the default PATH for the root user's regular shell being a reason to rewrite bash to systemd shell.
problem with vars is that they apply to any subsequent entry in the file so you need to take that into consideration; the nice thing about timers is that all settings are self contained and not affected by previous entries. The standard /10 and similar cron expressions also have thundering herd problem when on bunch of servers, tho some variants like in Jenkins use variant H/10 (H standing for hash) where the thing is randomly shifted in time to not hit same minute on same server/job
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.
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.
Total n00b here. My first linux install was pretty recently, in late 1996 or early 1997 (sometime that winter).
I just don't get it. Like is the core sentiment "How dare they address obvious system shortcomings"? Is it "I learned once and how dare you think I'm capable of learning again"? Is it "I want others to suffer the way I did to learn job scheduling"?
cron did a job, but had shortcomings. Systemd addresses many of those shortcomings. One day something else will come along and address the shortcomings of systemd, and no one will care about systemd nostolgia. This is how technology is supposed to work: making progress and fixing the shortcomings of the past generation. It's not a religion, we don't have to maintain the weird old ways from the 80's, your soul won't be saved by cron or corrupted by systemd.
Yeah, I certainly have my complaints about systemd but the parent's point is undermined by the fact that cron still works. If you prefer it, carry on I doubt seriously it's going anywhere. I still do sometimes.
I am not agreeing with egorfine. Indeed, why not improve what we can improve?
> cron did a job, but had shortcomings. Systemd addresses many of those shortcomings
Right, but what are those "many" shortcomings? The article lists four, and fully half of them seem to be nonsense, per my comment. (time spec syntax appears to be equally complex in systemd timers, and I have no idea what they mean about PATH, as it seems equal too)
The remaining two are fairly good points, kind of. Sending mail is a black hole until you look there, sure. Believing that emails get meaningfully delivered on a non-email server is very anachronistic. But isn't logging a black hole until you look there too?
So from the article that leaves "Execution history is difficult to follow and interrogate", which I super agree with. I would argue it's not inherent to cron, and one could have written a small tool that allows following and interrogating.
And… surely that goes for logging too? cron does log to syslog, right?
Maybe there's some integration with other stuff that is better, that I'm not aware of?
I'm not disputing that it's better. I'm sure it is. But where's that list? If it's literally only the `list-timers` command, then that's very underwhelming. Is it the randomness to scheduling? I've never needed it (I just spread them out over an hour by fixed start time), but sure that would have value in other cases where coordination is not possible. You could add it to cron, but not in a nice way.
To me it seems like engineers do what engineers like to do: enjoy greenfield implementations. It's open source. Nobody's going to ding your quarterly performance evaluation for going off on a amusement coding session without a requirements doc. I know that I have written a lot of tooling for amusement and to work the way I want it to work. I certainly understand the engineering mind that would rather write something from scratch than understand the previous system.
I don't mind learning new things, but this article seems to fawn over stuff you can do in systemd timers, where… yeah that was always an option (in cron). I don't have faith that the article writer actually knew cron before they trash it in favor of something else.
On a tangent, I do agree with egorfine that Lennartware inherently has a disdain for users and their workloads (e.g. kills user processes inside a screen/tmux arbitrarily), and that audio on linux was set back 5-10 years just from the mere disastrously bad quality of the pulseaudio implementation. It makes sense that he works for Microsoft.
* coalescing jobs with control over the granularity of it. That means you can say "i want this job run on at 14:30:02 exactly" and I want these jobs run at 19:21 or so, 19:22 or so: and 19:23 and set your resoultion to 10m and they'll all run at once. Great on laptops and other scenarios where you want to reduce power draw.
* System wakeup - you can wake a system from sleep various sleep modes (details depend on hw support) and run a job.
* cohesion with the rest of the system. this is a big deal when you stop playing with just your desktop and pet server and have to deal with 10^4 or more servers. having to deal with the wierd quirks of cron vs inittab vs whatever is frustrating and when there are many people working on it, someone is always going to do something quirky and fragile. Yes you have to know the systemd things, but that's it - a timer starts a unit, any unit, without all the bullshit (e.g, oh im stating with cron, these magic invocations are neeeded, oh im starting it with runit and these different invocations are needed, etc)
I literally never experienced any of the problems people complain about for pulseaudio - at the time it was released it was the smoothest audio experience i ever had on linux. I think some people just want to look cool and complain about the new thing.... But also I read manuals and think for 3 or 4 seconds before doing things, so maybe it has something to do with that.
I agree that's a good list. You did a better job than the article.
As for pulse audio: no, it has absolutely nothing to do with that. That's just being condescending and smug. I've never had a lithium battery fire, so that must mean manufacturing defects never cause them?
I get it. Some software had a couple bugs at first, as does all new software. And now some whiny people who have never, don't currently, and will never provide value to the open source ecosystem have spent more years whining and complaining about the bugs than the entire piece of software was in widespread use.
Wierd. I like systemd. It's given me more stability and control over my systems than anything before provided. I like pulseaudio - it made the linux audio experience better than anything that came before it.
I don't live in terror of new things though, so I don't really understand the propaganda.
> pulseaudio - it made the linux audio experience better
This is a take that is so drastically different to what I (and many other people) have experienced that it now makes sense that systemd is to your liking.
Yeah, it's sad that a few dozen very vocal people got upset that they would have to read the manual and maybe get rid of some of the hacky nonsense they cobbled together to get an equivalent experience to what default pulse provided. Those people have spent decades whining about imagined issues and preventing reasonable discourse about actually good software.
> 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.
> Ambiguous $PATH settings make cron script execution difficult to predict.
What makes you say that? 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?
> You might feel cool knowing the scheduling grammar by heart
I've used Linux since 1994 and I don't know it by heart. But luckily it's pre-printed in the crontab as comments:
You just put numbers aligned with the titles.The rest of the complaints, sure. Next time I need a cronjob, I'll try it out.