Terminate background python script nicely - python

I am running a python script in the background using the command python script.py &. The script might look like this.
import time
def loop():
while True:
time.sleep(1)
if __name__=='__main__':
try:
loop()
except KeyboardInterrupt:
print("Terminated properly")
When it comes to terminating the script, I would like to do some cleanup before it is stopped (such as printing "Terminated properly"). If I run as a current process, this would be handled by the except statement after a keyboard interrupt.
Using the kill PID command means the cleanup is never executed. How can I stop a background process and execute some lines of code before it is terminated?

You can use signal module to catch any signals sent to your script via kill.
You setup a signal handler to catch the signal in question that would perform the cleanup.
import signal
import time
running = 0
def loop ():
global running
running = 1
while running:
try: time.sleep(0.25)
except KeyboardInterrupt: break
print "Ended nicely!"
def cleanup (signumber, stackframe):
global running
running = 0
signal.signal(signal.SIGABRT, cleanup)
signal.signal(signal.SIGTERM, cleanup)
signal.signal(signal.SIGQUIT, cleanup)
loop()

Use finally clause:
def loop():
while True:
time.sleep(1)
if __name__=='__main__':
try:
loop()
except KeyboardInterrupt:
print("Terminated properly")
finally:
print('executes always')

Related

how to avoid a python script to hangs until both user uses ctrl+C & keep it possible

Was given a script I would reuse more or less, I need to be able to to both :
end the execution by itself
capture ctrl-c to exit on user action
I saw many clues to the second part on other answers/question of stackoverflow similar to :
try:
while True:
time.sleep(1)
except (KeyboardInterrupt, SystemExit):
pass
In my point of view I should run the execution functions (main) in
while mycondition:
try:
mainfunction()
except KeyboardInterrupt:
personalised_exit()
Why not (if I undersoud well as I am still a python noob), but why not a more declarative code with usage of signal modules ?
something might look then like
import signal
import sys
def signal_handler(sig, frame):
[...]
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
main()
signal.pause()

Python 3 KeyboardInterrupt Multithreading

I am trying to have a main thread wait for its worker threads to finish using the following code, but when I try to interrupt it with Ctrl+C it doesn't stop
import threading
import sys
exit = threading.Event()
#pass it to the threads
try:
exit.wait()
print('Goodbye')
sys.exit()
except KeyboardInterrupt:
print('Interrupted')
sys.exit()
UPDATE
Nothing prints. All background threads are daemons.
import threading
import sys
import time
exit = threading.Event()
#pass it to the threads
try:
print("hi")
time.sleep(20)
print('Goodbye')
sys.exit()
except KeyboardInterrupt:
print('Interrupted')
sys.exit()
Please try the above statement to test your code. i have tested it and its working fine for me.
As you are using exit.wait() without giving any timeouts, its running for infinite seconds. So please put some time as an agument.
Follow the below code:
exit = threading.Event()
#pass it to the threads
try:
print("hi")
exit.wait(5)
print('Goodbye')
sys.exit()
except KeyboardInterrupt:
print('Interrupted')
sys.exit()

When cancelling a Python script do something [duplicate]

This question already has answers here:
How do I capture SIGINT in Python?
(12 answers)
Closed 9 years ago.
When i press CTRL+C to cancel a running python script, is there a way to run a certain python code before the script terminates?
Use try/except to capture for KeyboardInterrupt, which is raised when you press CTRL+C.
Here is a basic script to demonstrate:
try:
# Main code
while True:
print 'hi!'
except KeyboardInterrupt:
# Cleanup/exiting code
print 'done!'
This will continually print 'hi!' until you press CTRL+C. Then, it prints 'done!' and exits.
CTRL+C raises KeyboardInterrupt. You can catch it just like any other exception:
try:
main()
except KeyboardInterrupt:
cleanup()
If you really don't like that, you can also use atexit.register to register cleanup actions to run (provided that you don't do something really nasty and cause the interpreter to exit in a funky way)
try:
# something
except KeyboardInterrupt:
# your code after ctrl+c
I'm pretty sure you just need a try/finally block.
Try out this script:
import time
def main():
try:
while True:
print("blah blah")
time.sleep(5)
except KeyboardInterrupt:
print("caught CTRL-C")
finally:
print("do cleanup")
if __name__ == '__main__':
main()
Output should be something like:
blah blah
caught CTRL-C
do cleanup
This code
import time
try:
while True:
time.sleep(2)
except KeyboardInterrupt:
print "Any clean"
gives
deck#crunch ~/tmp $ python test.py
^CAny clean
when I press Ctrl+C when executing.
You just have to handle KeyboardInterrupt exception.
Also you can deal with signals to set handlers.

Python: signal.pause() equivalent on Windows

I have my main application thread that spawns 2 threads and I catch SIGINT in my main thread to quit them nicely.
On linux, I'm using signal.pause() and it works perfectly.
What is the best way to implement signal.pause() on Windows?
My ugly solution is:
my_queue.get(True, averylongtime)
And put something in my_queue in my signal handler. Note that if I don't specify a timeout, SIGINT is not caught. But I wonder if there's a better solution.
Thank you
I use this:
#another:
while not self.quit:
# your code
# main
try:
# your code
except KeyboardInterrupt:
another.quit = True
time.sleep(5) # or wait for threading.enumerate() or similar
If I want it more robust, say, exit in presence of bugs too:
except KeyboardInterrupt:
another.quit = True
signal.alarm(5)
time.sleep(6)
A side effect to this is that every block where you except: or except Exception, e: (which is not something you should do anyway/much) you have to prepend except KeyboardInterrupt: raise so that the exception is not "eaten".
I use this for catching a ctrl-c on windows. In case I'm writing to a pipe or file or what have you.. I want to exit gracefully. Below is a toy example
import signal
import sys
def signal_handler(signal, frame):
print('Process Interrupted!\n\a')
sys.exit(0)
signal.signal(signal.SIGINT,signal_handler)
#Rest of your code

threading ignores KeyboardInterrupt exception

I'm running this simple code:
import threading, time
class reqthread(threading.Thread):
def run(self):
for i in range(0, 10):
time.sleep(1)
print('.')
try:
thread = reqthread()
thread.start()
except (KeyboardInterrupt, SystemExit):
print('\n! Received keyboard interrupt, quitting threads.\n')
But when I run it, it prints
$ python prova.py
.
.
^C.
.
.
.
.
.
.
.
Exception KeyboardInterrupt in <module 'threading' from '/usr/lib/python2.6/threading.pyc'> ignored
In fact python thread ignore my Ctrl+C keyboard interrupt and doesn't print Received Keyboard Interrupt. Why? What is wrong with this code?
Try
try:
thread=reqthread()
thread.daemon=True
thread.start()
while True: time.sleep(100)
except (KeyboardInterrupt, SystemExit):
print '\n! Received keyboard interrupt, quitting threads.\n'
Without the call to time.sleep, the main process is jumping out of the try...except block too early, so the KeyboardInterrupt is not caught. My first thought was to use thread.join, but that seems to block the main process (ignoring KeyboardInterrupt) until the thread is finished.
thread.daemon=True causes the thread to terminate when the main process ends.
To summarize the changes recommended in the comments, the following works well for me:
try:
thread = reqthread()
thread.start()
while thread.isAlive():
thread.join(1) # not sure if there is an appreciable cost to this.
except (KeyboardInterrupt, SystemExit):
print '\n! Received keyboard interrupt, quitting threads.\n'
sys.exit()
Slight modification of ubuntu's solution.
Removing tread.daemon = True as suggested by Eric and replacing the sleeping loop by signal.pause():
import signal
try:
thread=reqthread()
thread.start()
signal.pause() # instead of: while True: time.sleep(100)
except (KeyboardInterrupt, SystemExit):
print '\n! Received keyboard interrupt, quitting threads.\n'
My (hacky) solution is to monkey-patch Thread.join() like this:
def initThreadJoinHack():
import threading, thread
mainThread = threading.currentThread()
assert isinstance(mainThread, threading._MainThread)
mainThreadId = thread.get_ident()
join_orig = threading.Thread.join
def join_hacked(threadObj, timeout=None):
"""
:type threadObj: threading.Thread
:type timeout: float|None
"""
if timeout is None and thread.get_ident() == mainThreadId:
# This is a HACK for Thread.join() if we are in the main thread.
# In that case, a Thread.join(timeout=None) would hang and even not respond to signals
# because signals will get delivered to other threads and Python would forward
# them for delayed handling to the main thread which hangs.
# See CPython signalmodule.c.
# Currently the best solution I can think of:
while threadObj.isAlive():
join_orig(threadObj, timeout=0.1)
else:
# In all other cases, we can use the original.
join_orig(threadObj, timeout=timeout)
threading.Thread.join = join_hacked
Putting the try ... except in each thread and also a signal.pause() in true main() works for me.
Watch out for import lock though. I am guessing this is why Python doesn't solve ctrl-C by default.

Categories

Resources