1

I have a server script that is started by cron every 10 minutes and does some operations with database, so it can be running for several minutes. So as you see, the probability of overlapping the update process and script work is quite high while I can't afford that, since it can lead to DB corruption, etc.

My first thougt was to make some kind of locking mechanism, but everything I imagine becomes quite sophysticated: e.g. I'm thiking of having a PID file for running script with some kind of lock, but that leads to so many devil details, like correct locking, avoiding situations when script exits by error leaving .pid file on disk (preventing following runs), etc., etc.

My question then: is there a simple way to do this or some library/tool that solves this kind of problem?

Thank you!

lithuak
  • 111
  • 1

2 Answers2

4

The standard solution is to write the new version of the script to a new file with a temporary name in the same directory as the target. Once the script has been written it is renamed on top of the old version. Any running instance will still be using the old version.

If the script is called /usr/local/bin/script.sh the temporary name could be /usr/local/bin/.script.sh.XXXXXX where XXXXXX is replaced with a randomly generated string.

kasperd
  • 30,455
  • 17
  • 76
  • 124
  • Is it not sufficient that the file is created on the same filesystem as the destination? +1 for the atomic renaming to reliably switch to the new name. – Pekka Apr 05 '14 at 10:17
  • It is sufficient that it is on the same filesystem. All software I can think of using this approach does put it in the same directory. I suppose that's just the most obvious choice. – kasperd Apr 05 '14 at 10:20
  • An advantage in using something like `/tmp` prevents a prematurely terminating script from polluting the destination folder with unapplied updates. An administrator is more likely to clean up a well known directory. – Pekka Apr 05 '14 at 10:26
  • Using `/tmp` is not advisable as `/tmp` will often be a separate filesystem. Incomplete updates can be handled by the update script unlinking any files left over from a prior update attempt. Should you accidentally run two instances of the script in parallel, one may delete the temporary file from the other. That would cause one of the instances to fail and the other to succeed, the end result would however be that the update was applied, and no temporary files were left over. – kasperd Apr 05 '14 at 11:35
3

Just have your current cron script do it for you when it's done.

echo "cat /tmp/new.cron.sh > /usr/local/bin/current.cron.sh" >> /usr/local/bin/current.cron.sh
David Houde
  • 3,200
  • 1
  • 16
  • 19
  • Are there any drawbacks of this method of `echo ... >> cronfile.sh` compared to the answer from kasperd? (other than mild complexity of a script needing to know if it should overwrite itself, I don't want to rabit trail into the `if` scenarios there, just whether the `>>` is just as safe.) – Jesse Nov 28 '18 at 10:28