mitsuhiko/werkzeug — pull request #143 by dmayle (2011-12-14 22:11:40+00:00)
Title: Adding support for multiprocess servers to werkzeug.debug

In server environments that use a shared pool of processes, the werkzeug debbugger is unable to properly serve up traceback and frame information. This is a patch to allow it to work in that environment.

You can find a quick test script that sets up a process pool to allow testing this functionality here:

import os
import select
from werkzeug.wrappers import Request, Response
from werkzeug.debug import DebuggedApplication
import SocketServer

class PreForkingPoolMixIn(SocketServer.ForkingMixIn):

"""Mix-In class that keeps a pool of children to use for handling requests."""
def process_request(self, request, client_address):
"""Handle the request."""
try:
self.finish_request(request, client_address)
self.close_request(request)
except:
try:
self.handle_error(request, client_address)
finally:
self.close_request(request)

def serve_forever(self, poll_interval=0.5):
"""Handle one request at a time until shutdown.

Polls for shutdown every poll_interval seconds. Ignores
self.timeout. If you need to do periodic tasks, do them in
another thread.
"""
pid = True
self.active_children = []
for x in xrange(self.max_children):
if pid:
pid = os.fork()
if pid:
self.active_children.append(pid)
self._BaseServer__serving = True
self._BaseServer__is_shut_down.clear()
while self._BaseServer__serving:
# XXX: Consider using another file descriptor or
# connecting to the socket to wake this up instead of
# polling. Polling reduces our responsiveness to a
# shutdown request and wastes cpu at all other times.
if pid:
import time
time.sleep(1)
self.collect_children()
else:
r, w, e = select.select([self], [], [], poll_interval)
if r:
self._handle_request_noblock()
self._BaseServer__is_shut_down.set()

# Monkeypatch SocketServer with our Forking Pool
SocketServer.ForkingMixIn = PreForkingPoolMixIn

@Request.application
def application(request):
raise Exception('Forced')
return Response('Hello World!')

if __name__ == '__main__':
from werkzeug.serving import run_simple
run_simple('localhost', 4000, DebuggedApplication(application, evalex=True, multiprocess_support=True), processes=5)