summaryrefslogtreecommitdiff
path: root/paste/httpserver.py
diff options
context:
space:
mode:
authorianb <devnull@localhost>2007-04-12 04:00:38 +0000
committerianb <devnull@localhost>2007-04-12 04:00:38 +0000
commit7ece1ccb1f175a8d2a6d0953bb93fa2215b2ae75 (patch)
tree22f21e89a5f470eb58a561d353ca7707e11534b3 /paste/httpserver.py
parente2c41182a57cf9b5ab61784a8ebfdce9a2a0ecff (diff)
downloadpaste-7ece1ccb1f175a8d2a6d0953bb93fa2215b2ae75.tar.gz
Added a parameter to the threadpool: max_requests, which is the maximum number of requests to process in a worker thread before killing that thread. This should resolve problems with long-lived threads, as no thread lives too terribly long with this on. Also, turn the threadpool back on by default. And turn LimitedLengthFile back on when it is not an SSL connection
Diffstat (limited to 'paste/httpserver.py')
-rwxr-xr-xpaste/httpserver.py37
1 files changed, 25 insertions, 12 deletions
diff --git a/paste/httpserver.py b/paste/httpserver.py
index 4ac032a..29c2065 100755
--- a/paste/httpserver.py
+++ b/paste/httpserver.py
@@ -196,12 +196,11 @@ class WSGIHandlerMixin:
content_length = int(self.headers.get('Content-Length', '0'))
except ValueError:
content_length = 0
- #
- # @@: LimitedLengthFile is currently broken in connection
- # with SSL (sporatic errors that are diffcult to trace, but
- # ones that go away when you don't use LimitedLengthFile)
- #
- #rfile = LimitedLengthFile(rfile, content_length)
+ if not hasattr(self.connection, 'get_context'):
+ # @@: LimitedLengthFile is currently broken in connection
+ # with SSL (sporatic errors that are diffcult to trace, but
+ # ones that go away when you don't use LimitedLengthFile)
+ rfile = LimitedLengthFile(rfile, content_length)
remote_address = self.client_address[0]
self.wsgi_environ = {
@@ -526,7 +525,9 @@ class ThreadPool(object):
necessarily reliable. This is turned off by default, since it is
only a good idea if you've deployed the server with some process
watching from above (something similar to daemontools or zdaemon).
-
+
+ Each worker thread only processes ``max_requests`` tasks before it
+ dies and replaces itself with a new worker thread.
"""
@@ -534,6 +535,7 @@ class ThreadPool(object):
def __init__(
self, nworkers, name="ThreadPool", daemon=False,
+ max_requests=100, # threads are killed after this many requests
hung_thread_limit=30, # when a thread is marked "hung"
kill_thread_limit=1800, # when you kill that hung thread
dying_limit=300, # seconds that a kill should take to go into effect (longer than this and the thread is a "zombie")
@@ -547,6 +549,7 @@ class ThreadPool(object):
Create thread pool with `nworkers` worker threads.
"""
self.nworkers = nworkers
+ self.max_requests = max_requests
self.name = name
self.queue = Queue.Queue()
self.workers = []
@@ -798,7 +801,12 @@ class ThreadPool(object):
thread_obj = threading.currentThread()
thread_id = thread_obj.thread_id = thread.get_ident()
self.idle_workers.append(thread_id)
+ requests_processed = 0
while True:
+ if self.max_requests and self.max_requests < requests_processed:
+ # Replace this thread then die
+ self.add_worker_thread()
+ break
runnable = self.queue.get()
if runnable is ThreadPool.SHUTDOWN:
self.logger.debug('Worker %s asked to SHUTDOWN', thread_id)
@@ -813,6 +821,7 @@ class ThreadPool(object):
except ValueError:
pass
self.worker_tracker[thread_id] = [time.time(), None]
+ requests_processed += 1
try:
try:
runnable()
@@ -1059,13 +1068,10 @@ class ServerExit(SystemExit):
caught)
"""
-# @@: ThreadPool is currently broken, it shouldn't be the default till
-# it is thoroughly tested.
-#
def serve(application, host=None, port=None, handler=None, ssl_pem=None,
ssl_context=None, server_version=None, protocol_version=None,
start_loop=True, daemon_threads=None, socket_timeout=None,
- use_threadpool=False, threadpool_workers=10,
+ use_threadpool=True, threadpool_workers=10,
threadpool_options=None):
"""
Serves your ``application`` over HTTP(S) via WSGI interface
@@ -1232,7 +1238,8 @@ def server_runner(wsgi_app, global_conf, **kwargs):
'threadpool_kill_thread_limit',
'threadpool_dying_limit', 'threadpool_spawn_if_under',
'threadpool_max_zombie_threads_before_die',
- 'threadpool_hung_check_period']:
+ 'threadpool_hung_check_period',
+ 'threadpool_max_requests']:
if name in kwargs:
kwargs[name] = int(kwargs[name])
for name in ['use_threadpool', 'daemon_threads']:
@@ -1253,6 +1260,12 @@ server_runner.__doc__ = serve.__doc__ + """
You can also set these threadpool options:
+ ``threadpool_max_requests``:
+
+ The maximum number of requests a worker thread will process
+ before dying (and replacing itself with a new worker thread).
+ Default 100.
+
``threadpool_hung_thread_limit``:
The number of seconds a thread can work on a task before it is