1

If I start a python script every twelve hours with this crontab:

0 1,13 * * * /usr/bin/python script.py

Then how do I stop the script running inbetween?

I.E. I want the python script to start at 1am and 1pm, but stop the script at 6am and 6pm.

I'm doing this to get around the fact that making a particular script I have go to sleep for 6-12 hrs a day is proving beyond me! It seems better to hand the process over to the system itself.

1
  • Can you keep checking the time. By doing start_time = time.time() once and then current_time = time.time() periodically. and keep checking if its 6 hours. Commented Feb 19, 2015 at 19:21

3 Answers 3

3

I think you can write a new shell script in order to kill your python script And add a new line to crontab as illustrated below.

0 6,18 * * * /usr/bin/sh killPythonScript.sh

To kill python script you need to know pid of script. In order to get this info you can call script in a new shell script and get pid. Write that in a file , then when you want to kill process read pid from file.

Or try easier way which is killing script with its name. As an example, killPythonScript.sh should be like above

killall -g script.py

Or you can add this line directly to your crontab

0 6,18 * * * /usr/bin/sh killall -9 script.py

I tried to be clear. I hope it helps to you.

Sign up to request clarification or add additional context in comments.

Comments

1

One approach would be to have your Python script write its PID to the file system at a known path on startup and then remove the PID file when it exits. You could then schedule a cron job at 6 am/pm to run a script that uses the PID to send a terminate signal to the Python process - have the script look something like:

# Let's say this is in "kill_python.sh"
kill `cat /path/to/my/pidfile`

Then your crontab entry could look like:

0 6,18 * * * /bin/bash /path/to/kill_python.sh

Alternately, a far less precise and less preferable way might be to interrogate the process table looking for that process. Something like the following:

# Alternate implementation of "kill_python.sh"
kill `ps a | grep python script\.py | grep -v grep | awk '{ print $1 }'`

But this is far more error-prone, I endorse the first approach much more than this one. I'm including it in case for some reason it is not possible to trap the Python process's PID when it starts.

Comments

1

I thought I'd chime in with a way to do this in python, since you said that the only reason you're looking at crontab is because you couldn't figure out how to do it in python.

I'm using the library apscheduler which allows you to schedule your python scripts for run time later.

Here's an example that schedules a job for either 1a or 1p (whichever is next) and will end at 6a or 6p, respectively. When the job is finished it calls main() again which schedules the next job:

import datetime
from apscheduler.schedulers.background import BackgroundScheduler

def job_function():
    """Worker function that will be called at 1a or 1p everyday"""
    while True:
        if datetime.datetime.now().time() >= endtime:
            main()
            break

def main():
    """Main function that determines what time it is and when job_function() should be run next"""
    earlystart = datetime.time(hour=1)
    latestart = datetime.time(hour=13)
    now = datetime.datetime.now()
    global endtime
    if earlystart < now.time() > latestart:
        tomorrow = now.date() + datetime.timedelta(days=1)
        startdate = now.replace(day=tomorrow.day, hour=earlystart.hour, minute=0, second=0, microsecond=0)
        endtime = datetime.time(hour=6)
    else:
        if datetime.datetime.now() < earlystart:
            starthour = earlystart
            endtime = datetime.time(hour=6)
        else:
            starthour = latestart
            endtime = datetime.time(hour=18)
        startdate = now.replace(hour=starthour.hour, minute=0, second=0, microsecond=0)
    scheduler.add_job(job_function, 'date', run_date=startdate)

if __name__ == '__main__':
    scheduler = BackgroundScheduler()
    scheduler.start()
    main()

Let me know if you have any questions.

4 Comments

The second idea is good but it gives me this error (trying to do it so it sleeps at 1am): end_time = datetime.time(hour=1) TypeError: descriptor 'time' of 'datetime.datetime' object needs an argument
it sounds like you used from datetime import datetime, which means when you call datetime.time() you're really calling datetime.datetime.time() which actually is to create a new object and needs a descriptor. If you use that import make sure you remove the first datetime from all of the datetime.datetime.
I used import datetime to keep the namespace (I'm big into keeping namespaces so I don't screw anything up :) )
Ah gotcha. Thanks! Meanwhile, why can't I mark both this and the answer below as correct? The one below undoubtedly answers the question exactly but this one is more interesting as an alternative method... it seems unfair I can only mark one correct!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.