1

I found this interesting page that suggests several options:

  1. Create a lock file
  2. Create a PID file.
  3. flock
  4. solo

But what about his option:

Check ps to see if the executed command is currently running.

(A ps-check.sh script could even be included at the start of every cron job you create.)

I'm assuming that the reason I haven't come across this kind of solution is that it's a bad idea.

Why is this a bad idea?

ps-check.sh could return 1 if the command is already running. The cron script could call ps-check.sh like this:

#!/bin/bash
#some script

#get current script name into variable
#then use ps-check.sh to see if current script is already running
#by supplying it with 2 things: script name and current PID
me=`basename "$0"`    
if (( $(ps-check.sh $me $$) == 1)); then
  exit 1;
fi
# do more stuff

ps-check.sh would check to see if the script was already running under another PID.

Is there any case where a script would be running but not visible in ps? If sleeping?

EDIT - Conclusion:

I've decided to go with flock. Checking ps could work but I would probably have to handle a lot of conditions to make sure. I assume flock already handles most of those.

Buttle Butkus
  • 1,719
  • 8
  • 32
  • 45
  • Not a bad idea, but might not complete by itself. The `ps-check.sh` would assume some standards are followed and/or enforced and/or there is something unique you key from. If you are implementing this yourself and those around you follow your documented standards, then it could work just fine. People forget rules, especially friday afternoon at beer-30, or at 3am. What I am saying is, build some safety/sanity checks into your script so you don't nuke something critical. :-) – Aaron Jun 27 '17 at 00:45
  • @Aaron Thank you for your vote of confidence! I updated the question with some more details. What do you think? I am the only one currently writing any shell scripts or creating cron jobs on our servers. Everything was going fine until one script that was supposed to only take a few seconds and run every 10 minutes got stock and there ended up being hundreds of instances eating all resources. So this is to prevent that. – Buttle Butkus Jun 27 '17 at 01:35
  • As with anything, proper testing and documentation will go a long way when the day comes it isn't just you supporting your infrastructure. Looking back, there were plenty of times it was just me, or me and one other person supporting something I wrote. Today it is 68 people and I am not even on that team any more. It sounds like you are thinking this through and that is what matters most. – Aaron Jun 27 '17 at 03:26

2 Answers2

2

The flaw in using ps logic is that you expect a process name to be unique.

Unless you always start your processes with an absolute path a different user (or you yourself) can easily create a completely different process with the same name that would prevent your cron job from running.

HBruijn
  • 72,524
  • 21
  • 127
  • 192
  • I can see where that could be a problem, and how locks and PID files avoid that. So perhaps I should use one of those options. And I probably will. But, using the `ps` logic, if my scripts are very uniquely named, then it's likely that they would only be blocked if someone did so intentionally, right? Like if my scripts were all named like `buttlebutkus-clean-logs.sh` and `buttlebutkus-report-disk-usage.sh` – Buttle Butkus Jun 27 '17 at 05:11
  • I found this cool answer along the lines of what I was thinking of, but it doesn't solve the problem you bring up. https://stackoverflow.com/a/9271229/631764 – Buttle Butkus Jun 27 '17 at 05:21
1

I would recommend using run-one command - much simpler than dealing with the locks. From the docs:

run-one is a wrapper script that runs no more than one unique instance of some command with a unique set of arguments. This is often useful with cronjobs, when you want no more than one copy running at a time.

run-this-one is exactly like run-one, except that it will use pgrep and kill to find and kill any running processes owned by the user and matching the target commands and arguments. Note that run-this-one will block while trying to kill matching processes, until all matching processes are dead.

run-one-constantly operates exactly like run-one except that it respawns "COMMAND [ARGS]" any time COMMAND exits (zero or non-zero).

keep-one-running is an alias for run-one-constantly.

run-one-until-success operates exactly like run-one-constantly except that it respawns "COMMAND [ARGS]" until COMMAND exits successfully (ie, exits zero).

run-one-until-failure operates exactly like run-one-constantly except that it respawns "COMMAND [ARGS]" until COMMAND exits with failure (ie, exits non-zero).

Yuri Astrakhan
  • 151
  • 1
  • 7