Description
While the standalone server is processing a request, it cannot be killed with ordinary signals (e.g. SIGINT (Ctrl-C) or SIGTERM). Only SIGKILL ("kill -9") seems to work. This is because server_standalone spawns non-daemon threads, which block the process from terminating until they exit (see http://docs.python.org/lib/thread-objects.html, under setDaemon()).
Steps to reproduce
run moin ... server standalone in the foreground (attached to a terminal where you can use Ctrl-C to signal the process)
- start a request that takes a while (e.g. full-text search without indexes, or linkto: search)
- while the request is still running, hit Ctrl-C in the terminal where the server process is running
note that moin may print "Thanks for using MoinMoin!" to stdout (or its log file), but it does *not* terminate
when the request finishes and moin sends the response to the browser, then it terminates
The last two symptoms indicate that moin is receiving the SIGINT signal, but still keeps running.
This is particularly bad if running moin on underpowered hardware where you really did not mean to run that unindexed full-text search.
Example
See reproduction.
Component selection
MoinMoin.server.server_standalone
Note: a comment in server_standalone.py says that the twisted server has the same problem. I have not attempted to reproduce, investigate, or fix the problem in the twisted server. I suspect the problem and the fix are similar, though.
Details
MoinMoin Version |
1.7.1 |
OS and Version |
Ubuntu 7.04 (feisty fawn), Linux 2.6.20 |
Python Version |
2.5.1 |
Server Setup |
standalone |
Server Details |
|
Language you are using the wiki in (set in the browser/UserPreferences) |
en |
Workaround
kill -9 on the server process sometimes works, but not always. (This confuses me.)
Discussion
The fix is quite easy: threads created by the server process should be daemon threads. Here is a patch for server_standalone:
--- a/MoinMoin/server/server_standalone.py Mon Aug 18 14:49:18 2008 -0400 +++ b/MoinMoin/server/server_standalone.py Tue Aug 19 17:43:40 2008 -0400 @@ -133,6 +133,7 @@ class ThreadingServer(SimpleServer): return t = Thread(target=self.process_request_thread, args=(request, client_address)) + t.setDaemon(True) t.start() finally: self.lock.release() @@ -186,6 +187,7 @@ class ThreadPoolServer(SimpleServer): from threading import Thread for dummy in range(self.poolSize): t = Thread(target=self.serve_forever_thread) + t.setDaemon(True) t.start() SimpleServer.serve_forever(self)
One catch: after adding this, killing the server process works. However, I am seeing weird errors from doing that. Example:
2008-08-20 11:49:42,834 INFO MoinMoin.server.server_standalone:498 Thanks for using MoinMoin! Exception in thread Thread-4 (most likely raised during interpreter shutdown): Traceback (most recent call last): File "threading.py", line 460, in __bootstrap File "threading.py", line 440, in run File "/src/wiki/moin-1.7.1/lib/MoinMoin/server/server_standalone.py", line 220, in serve_forever_thread File "SocketServer.py", line 254, in finish_request File "/src/wiki/moin-1.7.1/lib/MoinMoin/server/server_standalone.py", line 290, in __init__ File "SocketServer.py", line 525, in __init__ <type 'exceptions.AttributeError'>: 'NoneType' object has no attribute 'exc_traceback' Unhandled exception in thread started by Error in sys.excepthook: Original exception was:
About half the time, moin seems to shut down cleanly on Ctrl-C (the client waiting for a response gets nothing, of course), and half the time I get that error. It always shuts down quite quickly after Ctrl-C, though, and that IMHO is the important thing.
Follow-up patch is to remove the comment and debug prints from the last person to look at this:
--- a/MoinMoin/server/server_standalone.py Tue Aug 19 17:43:40 2008 -0400 +++ b/MoinMoin/server/server_standalone.py Wed Aug 20 11:34:25 2008 -0400 @@ -165,11 +165,6 @@ class ThreadPoolServer(SimpleServer): This server is 5 times faster than ThreadingServer for static files, and about the same for wiki pages. - - TODO: sometimes the server won't exit on Conrol-C, and continue to - run with few threads (you can kill it with kill -9). Same problem - exist with the twisted server. When the problem is finally solved, - remove the commented debug prints. """ use_threads = True @@ -221,7 +216,6 @@ class ThreadPoolServer(SimpleServer): except: self.handle_error(request, client_address) self.close_request(request) - # sys.stderr.write('thread exiting...\n') def pop_request(self): """ Pop a request from the queue @@ -242,7 +236,6 @@ class ThreadPoolServer(SimpleServer): self.lock.wait() finally: self.lock.release() - # sys.stderr.write('thread exiting...\n') sys.exit() def die(self): @@ -258,7 +251,6 @@ class ThreadPoolServer(SimpleServer): def wake_all_threads(self): self.lock.acquire() try: - # sys.stderr.write('waking up all threads...\n') self.lock.notifyAll() finally: self.lock.release()
Plan
- Priority:
- Assigned to:
Status: Fixed by http://hg.moinmo.in/moin/1.7/rev/d996f53790bb