Remote shutdown your Python program
One piece of code for a project is written in Python and it does what it was intended to do but, out of the blue, I am asked about the possibility of shutting it down remotely from another computer (code is running on a server where I do not want other users to be messing around).
It was a perfect opportunity for using the threading library. So I went ahead and I wrote a small piece of code, encapsulated in a function, that will be run on a different thread. The main program is still doing its thing, but the new thread now creates a network socket and binds it to the proper IP address and port so it can accept connections from other computers over the network. When a new connection is made, the code will check if a special token is received, and if that is confirmed, it will shut down the whole program. Otherwise, the thread will loop forever in case new connections are made in the future.
So the question is how to shut down the program. Usually, I use exit(0) to make my program to finish (or it will just end if reaching the last line of code). But that will not work within a thread. So after a bit of googling around, I found that os._exit(0) will do the trick here. This can be called from the new thread to completely stop and finish the program.
But then I had a problem: my program now could be stopped remotely with no problem, however, when the program ended naturally, it will never stop. Why is that? Well ..., it turns out the main program, politely, will wait for the new thread to stop before finishing. Because my code features an endless loop, the new thread will never stop, thus causing the main program to never stop although it has finished doing its job. Ironically, the program can be successfully stopped remotely, and then it will stop entirely :-)
So the missing piece of the puzzle is the concept of daemon threads, which in Python are those that will finish as soon as the main program reaches its end. Depending on your version of Python you can just use the setDaemon(True) method on a Thread object or, if using Python 3, you set daemon=True in the threading.Thread( target = function, args = (1,), daemon = True ) constructor call.
If you need to signal anything from this new thread to the main program, you can use a global variable that will be shared among the two, so you can have some saying on how the main program works depending on the information that can be sent remotely to it, nice. In my case, I was not only allowing the program to be stopped remotely, but also to be paused at any given point, and later resumed (or stopped entirely).
Besides the code of the new thread (and importing os and threading libraries), I only needed to create a new daemon thread and started it, which can be done in a couple of lines. So this feature can be added this way to any other Python program you have.
It was a perfect opportunity for using the threading library. So I went ahead and I wrote a small piece of code, encapsulated in a function, that will be run on a different thread. The main program is still doing its thing, but the new thread now creates a network socket and binds it to the proper IP address and port so it can accept connections from other computers over the network. When a new connection is made, the code will check if a special token is received, and if that is confirmed, it will shut down the whole program. Otherwise, the thread will loop forever in case new connections are made in the future.
So the question is how to shut down the program. Usually, I use exit(0) to make my program to finish (or it will just end if reaching the last line of code). But that will not work within a thread. So after a bit of googling around, I found that os._exit(0) will do the trick here. This can be called from the new thread to completely stop and finish the program.
But then I had a problem: my program now could be stopped remotely with no problem, however, when the program ended naturally, it will never stop. Why is that? Well ..., it turns out the main program, politely, will wait for the new thread to stop before finishing. Because my code features an endless loop, the new thread will never stop, thus causing the main program to never stop although it has finished doing its job. Ironically, the program can be successfully stopped remotely, and then it will stop entirely :-)
So the missing piece of the puzzle is the concept of daemon threads, which in Python are those that will finish as soon as the main program reaches its end. Depending on your version of Python you can just use the setDaemon(True) method on a Thread object or, if using Python 3, you set daemon=True in the threading.Thread( target = function, args = (1,), daemon = True ) constructor call.
If you need to signal anything from this new thread to the main program, you can use a global variable that will be shared among the two, so you can have some saying on how the main program works depending on the information that can be sent remotely to it, nice. In my case, I was not only allowing the program to be stopped remotely, but also to be paused at any given point, and later resumed (or stopped entirely).
Besides the code of the new thread (and importing os and threading libraries), I only needed to create a new daemon thread and started it, which can be done in a couple of lines. So this feature can be added this way to any other Python program you have.
Comments