Reputation: 495
I want to execute my python file via crontab only if its down or not running already. I tried adding below entry in cron tab but it does not work
24 07 * * * pgrep -f test.py || nohup python /home/dp/script/test.py & > /var/tmp/test.out
test.py works fine if i run pgrep -f test.py || nohup python /home/dp/script/test.py & > /var/tmp/test.out
manually and it also works in crontab if i remove pgrep -f test.py || from my crontab and just keep 24 07 * * * nohup python /home/dp/script/test.py & > /var/tmp/test.out
Any idea why crontab does not work if i add pgrep -f? is there any other way i can run test.py just one time to avoid multiple running processes of test.py? Thanks, Deepak
Upvotes: 5
Views: 4867
Reputation: 618
You can create a test file by the name test.py If you try executing the same file again it should quit.
import time
import os
from tempfile import TemporaryFile
import subprocess
def cron_running(p_name):
run_cnt=0
with TemporaryFile() as tf:
subprocess.call(["ps","ax"], stdout=tf)
tf.seek(0)
for line in tf:
if p_name in line.decode('ascii'):
run_cnt+=1
if run_cnt > 1:
quit()
if cron_running(os.path.basename(__file__)):
print("cron is already running")
quit()
for i in range(60):
time.sleep(1)
Upvotes: 0
Reputation: 331
Why just check pid is already running like this
Pid = os.popen('pgrep -f myscript.py').readlines()
if len(Pid) > 1:
exit()
Upvotes: 0
Reputation: 1094
The problem is the pgreg -f
is recognizing the shell script that cron uses to run the command itself.
I solved the pgrep -f
problem by encoding the file name in rot13 and decoding it with a python one-liner, since I didn't want to add a script wrapper just for the cron job. i.e.:
pgrep -f $(python3 -c 'import codecs; print(codecs.decode("grfg.cl", "rot13"))') || nohup python /home/dp/script/test.py & > /var/tmp/test.out
Added: You can use tr to decode rot13 which would result in a shorter and easier to read command:
pgrep -f $(echo grfg.cl | tr a-zA-Z n-za-mN-ZA-M) || nohup python /home/dp/script/test.py & > /var/tmp/test.out
Upvotes: 0
Reputation: 744
Came across this old question looking for solution myself.
Use psutil:
import psutil
import sys
from subprocess import Popen
for process in psutil.process_iter():
if process.cmdline() == ['python', 'your_script.py']:
sys.exit('Process found: exiting.')
print('Process not found: starting it.')
Popen(['python', 'your_script.py'])
You can also use start time of the previous process to determine if it's running too long and might be hung:
process.create_time()
There is tons of other useful metadata of the process.
Upvotes: 1
Reputation: 3159
I did the test with a script.py
running an infinite loop. Then
pgrep -f script.py
...from the terminal, gave one pid, 13132
, while running from cron:
pgrep -f script.py > /path/to/out.txt
outputs two pids, 13132
and 13635
.
We can therefore conclude that the command pgrep -f script.py
lists itself as a match, when run from cron. Not sure how and why, but most likely, this is indirectly caused by the fact that cron
runs with a quite limited set of environment variables (HOME, LOGNAME, and SHELL).
Running pgrep -f
from a (wrapper) script makes the command not list itself, even when run from cron
. Subsequently, run the wrapper from cron
:
#!/bin/bash
if ! pgrep -f 'test.py'
then
nohup python /home/dp/script/test.py & > /var/tmp/test.out
# run the test, remove the two lines below afterwards
else
echo "running" > ~/out_test.txt
fi
Upvotes: 7
Reputation: 4250
It is generally a good idea to check whether the application is running or not within the application rather than checking from outside and starting it. Managing the process within the process rather than expecting another process to do it.
This will ensure that you will have more control over the life time of a process AND let you decide what to do in case of failures.
Not to mention, if you want to make sure that the application up time is to be high, it is best to make use of monitoring services such as Monit. Again this will depend on your application to add a sanity layer that says whether it is OK or not.
Upvotes: 3
Reputation: 22433
cron may be seeing the pgrep -f test.py
process as well as the test.py
process, giving you the wrong result from pgrep
.
Try the command without the -f
, this should just look for an occurrence of test.py
or replace -f
with -o
which will look for the oldest occurrence.
Your other option is to insert into test.py something along the lines of:
Pid = os.popen('pgrep -f test.py').read(5).strip()
which will allow you to check within the code itself, if it is already running.
Upvotes: 1