Is there a way for me to tell cron to run an app BUT not run it if a process exist already?
7 Answers
the simplest way, use pgrep
in crontab:
* * * * * pgrep processname > /dev/null || /path/to/processname -args0 -args1
-
1Love the simplicity of this answer. FYI, you should be able to add the -f flag to pgrep, and you can then check the full process name, which is useful if you also want to inspect the arguments to the process as part of your condition. May 7, 2014 at 8:59
-
6No, you can't use the -f flag with pgrep inside a cronjob. The reason is that you'll match against the shell script used to run the cronjob itself. Jul 27, 2015 at 23:34
-
When running a GUI process with cron, prepend with
export DISPLAY=:0
to preventCould not connect to display
errors.* * * * * export DISPLAY=:0 && pgrep processname > /dev/null || /path/to/processname -args0 -args1
– BenjamMar 8, 2018 at 17:17
Run a script, instead of directly the program. There are many possibilities. For example :
MYPROG="myprog"
RESTART="myprog params"
PGREP="/usr/bin/pgrep"
# find myprog pid
$PGREP ${MYPROG}
# if not running
if [ $? -ne 0 ]
then
$RESTART
fi
-
1FYI -- using scalar variables to store argument lists is considered bad practice. See mywiki.wooledge.org/BashFAQ/050 for an example of a case where it fails. Dec 4, 2013 at 15:59
-
...similarly,
pgrep myprog; if [ $? -ne 0 ]; then ...
would be better written asif ! pgrep myprog; then ...
Dec 4, 2013 at 16:00 -
...this latter style is not only more readable, but also less error-prone: It's easy to unintentionally disrupt the value of
$?
, for instance by adding log messages or error handling between lines. Dec 4, 2013 at 16:00
This script will not run again if the previous instance hasn't finished. If you want to not run something if another specific process is running, see harrymc's script.
DATE=`date +%c`;
ME=`basename "$0"`;
LCK="./${ME}.LCK";
exec 8>$LCK;
if flock -n -x 8; then
echo ""
echo "Starting your script..."
echo ""
[PUT YOUR STUFF HERE]
echo ""
echo "Script started $DATE";
echo "Script finished `date +%c`";
else
echo "Script NOT started - previous one still running at $DATE";
fi
You could use a lock file in your script, but please see Process Management.
flock
is one utility that can be used.
-
good one! now rsync over this slow line can take all the time it needs, firing within 5 minutes of the client host coming on line without manual intervention:
*/5 * * * * root flock /run/shm rsync -auhx --numeric-ids -e "ssh -T -c arcfour128 -o Compression=no -x" [source] [user]@[host]:[dest]
– eMPee584Jan 7, 2016 at 19:54
This is usually handled by the program itself rather than by cron
. There are two standard techniques for this:
1) grep
the output of ps
to see whether there's a process by that name already running
2) On startup, first check for the existence of a pid (process id) file, usually at /var/run/program_name.pid
, and, if it exists, read the pid out of the file and check whether that process still exists; if it does, refuse to start. If the pid file doesn't exist or the pid in the file has gone away, then create a pid file, write your process id into it, and continue on with normal startup.
While it's technically possible to write bash pipes that will do either of these directly into your crontab, it's better to add them to the program being started (so that they'll apply no matter how it gets started) or to write a wrapper script to handle this, as harrymc suggested.
* * * * * pgrep -f "[p]attern" > /dev/null || /path/to/processname -args0 -args1
I have reused the above answer with an improvement in pattern matching. pgrep without f option doesnot match process pattern. Yet there is a problem with using f option. With f option, the shell spawning the cron is always matched and returns its pid hence the process is never restarted.
Adding a [] around one of the letters pattern matches only the process and the pid of cron shell is not returned.
Docs: https://www.timkay.com/solo/
solo is a very simple script (10 lines) that prevents a program from running more than one copy at a time. It is useful with cron to make sure that a job doesn't run before a previous one has finished.
Example
* * * * * solo -port=3801 ./job.pl blah blah