Stopping threads created by BaseHTTPServer using ThreadingMixin

I read this post here using ThreadingMixin (from the SocketServer module), you can create a stream server with BaseHTTPServer . I tried and it works. However, how to stop active threads created by the server (for example, during server shutdown)? Is it possible?

+4
source share
2 answers

The easiest solution is to simply use daemon_threads . Short version: just set this to True and don't worry about it; when you exit, all threads still running will automatically stop.

As ThreadingMixIn docs say:

When inheriting from ThreadingMixIn for streaming connectivity behavior, you must explicitly declare how you want your threads to behave on a sudden shutdown. The ThreadingMixIn class defines the daemon_threads attribute, which indicates whether the server should wait for the thread to finish. You must explicitly set the flag if you want the threads to run autonomously; False by default, which means that Python will not terminate until all threads created by ThreadingMixIn are completed.

More information is available in threading docs :

A thread can be marked as a "daemon thread". The value of this flag is that the entire Python program exits when only daemon threads remain. The initial value is inherited from the creating thread. The flag can be set through the daemon property.

Sometimes this is not suitable because you want to disconnect without logging out or because your handlers may have a cleanup that needs to be performed. But when appropriate, you cannot simplify.

If all you need is a way to shutdown without logging out and does not need guaranteed cleanup, you can use the APIs to terminate the streams using ctypes or win32api . This is usually a bad idea, but sometimes this is what you want.

If you need a clean shutdown, you need to build your own technique for yourself where the threads interact. For example, you can create a global "leave flag" variable protected by threading.Condition , and periodically check its handle function.

It's great if threads just do a slow, non-blocking job that you can break down into smaller parts. For example, if the handle function always checks the exit flag at least once every 5 seconds, you can guarantee that threads can be turned off for 5 seconds. But what if threads work with locking - as they probably are, because the whole reason you used ThreadingMixIn was that you make blocking calls instead of writing select loops or using asyncore or the like?

Ok, no good answer. Obviously, if you just need to complete the work “in the end” and not “in 5 seconds” (or if you are ready to refuse a clean shutdown in 5 seconds and return to using the platform’s APIs or demonstrating threads), It can simply put checks before and after each blocking call, and it will work “often”. But if that is not good enough, you really cannot do anything.

If you need it, the best answer is to change your architecture to use an infrastructure that has ways to do this. The most popular are Twisted , Tornado and gevent . In the future, PEP 3156 will bring similar functionality to the standard library, and there is a partially complete tulip reference implementation that you should play on if you are not trying to create something for the real world, which should be ready in the near future.

+7
source

Here is a sample code showing how to use threading.Event to shut down the server for any POST request,

 import SocketServer import BaseHTTPServer import threading quit_event = threading.Event() class MyRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): """This handler fires the quit event on POST.""" def do_GET(self): self.send_response(200) def do_POST(self): quit_event.set() self.send_response(200) class MyThreadingHTTPServer( SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer): pass server = MyThreadingHTTPServer(('', 8080), MyRequestHandler) threading.Thread(target=server.serve_forever).start() quit_event.wait() server.shutdown() 

The server is shutting down, so you can immediately restart the server and the port is accessible, rather than receiving "Addresses already in use."

0
source

All Articles