OpenBSD cron(8) now supports random ranges with steps
undeadly.org
undeadly.org
Once again, OpenBSD with the simple, obvious solution, that everyone else kinda overlooked. I hope every other cron out there copies and ships this as soon as possible.
Systemd Timers have had this for a while.
Personally I find the OpenBSD solution far more elegant and UNIXy than the systemd one, but to each their own.
What would you say is wrong with RandomizedDelaySec?
[Timer]
OnCalendar=daily
RandomizedDelaySec=12h
might take few more seconds to type, but it's definitely readable without any additional documentation.https://www.freedesktop.org/software/systemd/man/systemd.tim...
Ie seconds if no units specified.
Sounds like a lousy standard if the correct way to use it is to say "I want to delay by 12 hour seconds". What is even "12 hour seconds"?
"Sec" suffix indicates time and implements a default of seconds, where a suffix to the value indicates a change in unit.
It would be like Asking "Memory Allocation(MB)" but accepting "12G" for 12 GB.
RandomizedDelaySec=Even if their cron does...
Proper design reduces complexity. The above adds a lot of complexity, and thus it's a hack. Not the appearance.
Otherwise with your standard of hack anything beyond hello world and baby's first input are hacks because everything else requires boilerplate.
https://github.com/freebsd/freebsd-src/commit/f5896baf9c429c...
For example, instead of "0-59/10" in the minutes field, "0~59/10" can be used to run a command every 10 minutes where the first command starts at a random offset in the range [0,9]. The high and low numbers are optional, "~/10" can be used instead.But the above point is still true: many jobs take a few minutes to run. 60s of dispersion in start time is better than nothing, but you really want more.
(In this case, things are still quantized to a minute boundary, so you'd really want both).
If the delay is at the reading side, away from Akami, through a cache, perhaps 10 concurrent requests for X would result in ten lots of data transfer as it isn't in cache yet, but 10 with a short delay is enough to prime the local cache on the first request before the rest start.
There are a number of reasons a sudden glut of activity could balloon bandwidth or CPU/memory costs more than you might expect.
Without a chunk more detail about the system in question, this is just random speculation of course.
Thinking about this-- this is Akamai, who has historically charged for midgress. Liveness of cache could be very important.
They're on different timescales. The OpenBSD start times are still quantized to the minute, I believe.
Both solutions would complement each other.
It was such a breath of fresh air compared to Linux at the time because it was a coherent, engineered, documented system. When you didn't always have reliable internet (and at least for me, even when I did have it was something like 128K DSL), it was a huge deal to have well written man pages, where as on the linux half the time time the man page woud just tell you to scream into the void, err, run gnu info.
This was still in the period when the GPL scared off corps.
It kind of feels like this is putting the policy of "don't all go at once" into the cron mechanism, which is just starting jobs at desired times.
sleep $((RANDOM%=60))
...or longer, at the top of the script your cron is running.
Firstly, OpenBSD is a niche OS, meaning the absolute magnitude of OpenBSD cron jobs out "in the wild" is relatively low.
Second, my understanding is that this is a client-side feature. I.e. if I run a service, this feature only benefits me if a significant portion of my users opt into it.
Third, I have an unsubstantiated suspicion that cron usage relative to systemd usage is also on the decline.
I have to say, these flags are a really nice enhancement to cron.
https://man.freebsd.org/cgi/man.cgi?query=crontab&apropos=0&...
https://man.netbsd.org/NetBSD-9.3-STABLE/crontab.5
http://fcron.free.fr/doc/en/fcrontab.5.html#FCRONTAB.5.ERROR...
Just because it doesn’t consider external executions, it doesn’t mean it’s a bad solution. Horses for courses etc
No, it's gross. By providing that facility in the wrong place it discourages implementing it in the right place to people who come at the problem from the cron perspective.
Wrap the command in a flock-running script. That script goes in the crontab entry. When you're inevitably debugging your cron-scheduled command - paydirt! The command serializes itself still while you're manually testing instead of shitting itself.
How did the lock fail? Was there a more reliable fix?
* It's not just cron that can cause concurrent execution, and if that matters you generally want to robustly prevent it - not just if cron is the executor.*
So you did not like that exclusion only worked when triggered from cron. But in your case it also only works when triggered from your script. So cron just made your script an integrated feature and you’re essentially criticizing your own solution.
If it's a single command or pipeline... adding the layer of indirection to have a script that runs flock is more opaque. Might as well put it in cron and trust cron to only run it once.
I like flock(1) and have known how to use it for 15 years. But there's sharp edges.
- It's not standardized. In particular, this means the OpenBSD base system doesn't even include it. It's not like the underlying flock(2) is very well behaved or consistent.
- You need to ask for nonblocking behavior.
- If your command or script can ever result in a daemon launching, it may be holding the lock even though the part of your action that is supposed to be protected by the lock (the script/immediate subprocess) has ceased. so e.g. 'flock -n /tmp/relaunch-apache /etc/init.d/apache2 restart' could be a really bad idea. -u can fix this... in some cases.
You are confusing running a process with running a task from scheduler.
You are aware that flock(1) is a thing, right? And that a defacto core tenet of UNIX is composability of disparate programs that do one thing well?
cron goes completely against that principle - after all, you can schedule jobs with the 'at' command, and to make a repeating task, you just make it exec 'at' again each time it is called. cron is for the lazy, no real UNIX hacker would dream of using such an extravagant single-use program. /s
No. Maybe I heard and even knew what it is, but I never needed it.
You know why?
My task scheduler supports running only one instance of the task so I don't need to reinvent the wheel every time I need something to run on schedule.
Just 'somebinary args args args', 'run only one instance' and I'm done.
> flock - manage locks from shell scripts
Well, yep. Reinventing the wheel each other time.
Thanks, I have some more important things (like browsing HN) than writing shitty shell scripts.
Erm, no - flock(1) is a UNIX tool, a component if you will. It's the exact opposite of reinventing the wheel.
Not understanding the operating system you're using is fine, but it's good to at least know what you don't know.
If I need to write a wrapper script each time I need to run a task on a timer - then it is the proverbial reinventing the wheel. It doesn't matter if you call it a tool, utility or a component. Especially if this was solved decades ago.
> Not understanding the operating system you're using is fine
Ah, another mighty UNIX wizard here.
And there's your problem - you don't realize "writing a wrapper script" is actually simpler than messing with config files.
Come on, I would repeat it again - it was solved for decades. Why do you need to do the things like it's 1976? Why do you insist everyone else should do that way too and abandon the fruits of the digital age?
It was solved decades ago: in 1976. I don't understand why you feel like it wasn't.
EDIT: In addition, the Task Scheduler in Windows has this type of option, so it may help those sys admins coming from that environment, leveraging their existing knowledge
In crons that do not support something like this, you can introduce a random delay with a Perl oneliner. For example,
# Start within the first 10 minutes of a matching hour.
0 */8 * * * perl -e 'sleep rand 10*60' && ~/.config/jobs/fetch-tcl-logs 0 */8 * * * sleep "$(jot -r 1 0 599)" && ~/.config/jobs/fetch-tcl-logs sleep $((RANDOM % 600)) && fetch-tcl-logs #!/bin/bash
set -e
HEIIONCALL_API_KEY="redacted_api_key_goes_here"
HEIIONCALL_TRIGGER_ID="redacted_trigger_id_goes_here"
AUTHORIZATION_HEADER="Authorization: Bearer ${HEIIONCALL_API_KEY}"
CHECKIN_URL="https://api.heiioncall.com./triggers/${HEIIONCALL_TRIGGER_ID}/checkin"
if [ "$1" != "--now" ]; then
RANDOM_SLEEP=$[ ( $RANDOM % 55 ) + 1 ]
echo "Sleeping ${RANDOM_SLEEP} seconds before checkin..."
sleep ${RANDOM_SLEEP}s
fi
echo "Checking in..."
exec curl \
-X POST \
--retry 5 --retry-connrefused --retry-max-time 15 --retry-delay 1 \
-H "${AUTHORIZATION_HEADER}" \
"${CHECKIN_URL}"
This script ~/bin/heiioncall-checkin.sh gets called by crond every minute at exactly :00 seconds, so my expected maximum timeout between check-ins is approximately 120 seconds. And I can skip the sleep with "--now" flag for testing. But I'd much rather have this random offset behavior be something optionally built-in to cron, I suppose.[1]: https://www.freedesktop.org/software/systemd/man/systemd.tim...
E.g. Tor network capacity varies over the month due to bandwidth management tending to happen at the begining/end of months
I put together a small busybox-like collection of sysadmin tools, and one of the subcommands is "splay" to sleep for a random amount of time. It's one of those things that is useful surprisingly often, even outside cron.
Btw congrats to the openbsd people for catching up.
Also, just as a sidenote I'm not willing to seriously discuss: I seriously doubt I'd personally ever use random ranges in production. I understand what problem it's supposed to solve, but generally I just really don't want anything random in my systems. If it conflicts with some other cronjobs or whatever, I'd like it to break down deterministically — preferably, all the time, so it's easier to spot, track down and fix it. If it causes any load spikes, I'd like these spikes to be regular, so that I can see that and manually tweak run times so that it'll be more even. If any problems arise, I'd prefer them to arise after somebody changed something, and not just magically one Saturday evening a couple of months later.
The only situation I can think of right away when this is acceptable, is if I have lot of nodes with the same cron config, so it's my attempt to spread out workers of the same type that I know would start at the same time otherwise. But then, why the fuck do I have such a degenerate architecture in the first place?! Maybe I should think about replacing that by something a little more sustainable, like, uh, a centralized scheduler? No, I mean, it's definitely a solution — a quick and easy one, at that — but even then it seems like a solutions to a problem that shouldn't have existed in the first place.