Prevent duplicate cron job running
pankajtanwar.in
pankajtanwar.in
How, exactly ?
I've been a cron user forever, I had never heard of systemd timers until this thread.
A quick internet search shows:
- Nice clean config in a file (instead of having to edit crontab)
- Lots of great features that you would have to manually implement and maintain in cron (e.g. missed launches, duplicate runs, random delay, timeouts)
I mean sure, I've got bash script templates that let me solve the problem of preventing duplicate cron job running.But having seen how easy it is to achieve the same thing with systemd timers whilst not requiring a whole lot of boilerplate code in each shell file ... why wouldn't you switch to systemd timers ? I sure will be.
I like systemd. It's a good clone of launchd
Hmm, let's see ...
- Choice 1: Use what comes with my system (two choices, systemd or, if for the anti-systemd people... cron)
- Choice 2: Install some random third-party that has not had any substancial git commits since 2014 (the 2019 commits are just admin metadata).https://man.openbsd.org/crontab.5
"-s command
Only a single instance of command will be run concurrently. Additional instances of command will not be scheduled until the earlier one completes."
But I don't think it saves the state somewhere permanently, which isn't a big problem until cron's process dies for some reason.
The approach you're suggesting is what led to the problem you're proposing it as a solution for.
That said systemd-timers, as mentioned in many other comments, is probably the right answer here.
The problem with creating files is that you then have the stale lock file problem to deal with which adds a lot more complication.
There's also sysv or posix semaphores.
A simple flock doesn't always work all that well - the devil is in the details. And there is the issue that you miss a run of the script and have to wait another half hour for the next run.
I've used the Highlander, "There can be only one!" code pattern for forever, and it works really well:
https://www.perlmonks.org/?node_id=14260
You could change things to check on the status of your lock every minute or so for 15 minutes or whatever.
Also in module form,
https://metacpan.org/pod/App::Highlander
And much more updated:
https://medium.com/booking-com-development/highlander-b67172...
No need to attempt to stuff all this in a cronjob IMHO.
It does. (https://docs.python.org/3/library/fcntl.html#fcntl.flock)
glances around nervously is flocking one of those "what's old is new again" concept that people are just now relearning? Surely a blog post on how not to have two concurrent cronjobs running is kind of a weird thing to read when some Linux grey beard figured this out in the 90's on their lunch break.
> SQLite uses POSIX advisory locks to implement locking on Unix. On Windows it uses the LockFile(), LockFileEx(), and UnlockFile() system calls. SQLite assumes that these system calls all work as advertised. If that is not the case, then database corruption can result. One should note that POSIX advisory locking is known to be buggy or even unimplemented on many NFS implementations (including recent versions of Mac OS X) and that there are reports of locking problems for network filesystems under Windows. Your best defense is to not use SQLite for files on a network filesystem.
I guess cross-platform for naive me is POSIX + Windows.
https://git.dpkg.org/cgit/dpkg/dpkg.git/commit/utils/start-s...
If you're writing the program, it's fairly easy to do yourself in it with Flock or Fcntl (you can usually just get an exclusive lock in the absolute path to the running executable/script.
That said, quite a few of those moreutils items are useful in their own right (e.g. ts to prefix timestamps to each line of output is something so simple but so useful for logging output, chronic to silence stdout unless exit error is also very useful for cron, etc).
$ rpm -qi moreutils | grep Size
Size : 194354
$ rpm -qi util-linux | grep Size
Size : 11565734
So, < 200k compared to > 11MB based on compressed package, or if you want more specific counts for moreutils: $ rpm -ql moreutils | grep -v build-id | xargs du -hc
4.0K /usr/bin/chronic
4.0K /usr/bin/combine
20K /usr/bin/errno
24K /usr/bin/ifdata
16K /usr/bin/ifne
20K /usr/bin/isutf8
16K /usr/bin/lckdo
16K /usr/bin/mispipe
16K /usr/bin/pee
20K /usr/bin/sponge
8.0K /usr/bin/ts
8.0K /usr/bin/vidir
4.0K /usr/bin/vipe
4.0K /usr/bin/zrun
24K /usr/share/doc/moreutils
4.0K /usr/share/man/man1/chronic.1.gz
...
4.0K /usr/share/man/man1/zrun.1.gz
260K total
The very small utils are actually perl scripts so there's a few dependencies it may pull in there (especially if there's no Perl in the container already, but this is for CentOS so people might be using different base containers.But honestly, a package made that excludes the perl portions would be ideal for containers. From what I can tell, there's no other libraries used except glibc, and then you get most of those implemented in ~20k or less each.
$ rpm -ql moreutils | grep bin/ | xargs -n1 ldd | cut -d'(' -f1 | sort | uniq
/lib64/ld-linux-x86-64.so.2
libc.so.6 => /lib64/libc.so.6
linux-vdso.so.1
not a dynamic executable
If the perl was split into separate packages (CentOS already ships moreutils and moreutils-parallel to split that out), that would be ideal for containers for the portions that are binaries, IMO.