Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python - Infinite loop script running in background + restart

I would like to have a python script that runs in background (infinite loop).

def main():
    # inizialize and start threads
    [...]

    try:
        while True:
            time.sleep(1)

    except KeyboardInterrupt:
        my.cleanup()

if __name__ == '__main__':
    main()
    my.cleanup()
  1. In order to have the application run constantly in infinite loop what is the best way? I want to remove the time.sleep(1) which I don't need

  2. I would like to run the script in background nohup python myscript.py & is there a way to kill it "gracefully"? When I run it normally hitting the CTRL+C my.cleanup() is called, is there a way to call this when the kill command is used?

  3. What if I would like (using cron) kill the script and restart it again? Is there a way to make it do my.cleanup()?

Thank you

like image 687
d82k Avatar asked Sep 28 '22 22:09

d82k


1 Answers

  1. In order to have the application run constantly in infinite loop what is the best way? I want to remove the time.sleep(1) which I don't need

A while True or while <condition> loop is OK, in my opinion.

A sleep() is not mandatory for such a infinite loop as long as you don't require your program to wait for a certain time period.

  1. I would like to run the script in background nohup python myscript.py & is there a way to kill it "gracefully"? When I run it normally hitting the CTRL+C my.cleanup() is called, is there a way to call this when the kill command is used?

You may want to "listen" to serveral signals using the signal() method from the package "signal".

Simplified example extended by signal hooks:

import time
import signal

# determines if the loop is running
running = True

def cleanup():
  print "Cleaning up ..."

def main():
  global running

  # add a hook for TERM (15) and INT (2)
  signal.signal(signal.SIGTERM, _handle_signal)
  signal.signal(signal.SIGINT, _handle_signal)

  # is True by default - will be set False on signal
  while running:
    time.sleep(1)

# when receiving a signal ...
def _handle_signal(signal, frame):
  global running

  # mark the loop stopped
  running = False
  # cleanup
  cleanup()

if __name__ == '__main__':
  main()

Note, that you can't listen to SIGKILL, when terminating a program using that signal, you have no chance to do any clean up. Your program should be aware of that (an do kind of pre-start clean up or fail with a proper message).

Note, I was using a global variable to keep this example simple, I prefer to encapsulate this in a custom class.

  1. What if I would like (using cron) kill the script and restart it again? Is there a way to make it do my.cleanup()?

As long as your cronjob will kill the program with any signal except SIGKILL this is possible, of course.

You should consider doing what you want to do in a different way: for example, if you want to "re-do" some setup task before the infinite loop task, you could also do this upon a certain signal (some programs use SIGHUP for reloading configrations, for example). You'd have to break the loop, do the task and resume it.

like image 199
try-catch-finally Avatar answered Oct 06 '22 20:10

try-catch-finally