changeset 1170:a8aca1c131a9

thfcgi: limit max. number of requests
author Thomas Waldmann <tw AT waldmann-edv DOT de>
date Sun, 13 Aug 2006 19:11:23 +0200
parents 7794b6947a06
children 28120c8c1b6b
files MoinMoin/support/thfcgi.py wiki/server/moin.fcg
diffstat 2 files changed, 30 insertions(+), 52 deletions(-) [+]
line wrap: on
line diff
--- a/MoinMoin/support/thfcgi.py	Sun Aug 13 19:11:12 2006 +0200
+++ b/MoinMoin/support/thfcgi.py	Sun Aug 13 19:11:23 2006 +0200
@@ -245,11 +245,11 @@
     """A request, corresponding to an accept():ed connection and
     a FCGI request."""
 
-    def __init__(self, conn, req_handler, multi=1):
+    def __init__(self, conn, req_handler, inthread=False):
         """Initialize Request container."""
         self.conn = conn
         self.req_handler = req_handler
-        self.multi = multi
+        self.inthread = inthread
 
         self.keep_conn = 0
         self.req_id = None
@@ -371,7 +371,7 @@
         rec.writeRecord(self.conn)
         if not self.keep_conn:
             self.conn.close()
-            if self.multi:
+            if self.inthread:
                 raise SystemExit
 
     #
@@ -515,10 +515,10 @@
         data = data[8192:]
         return chunk, data
 
-class FCGIbase:
-    """Base class for FCGI requests."""
+class FCGI:
+    """FCGI requests"""
 
-    def __init__(self, req_handler, fd, port, requests_left, backlog):
+    def __init__(self, req_handler, fd=sys.stdin, port=None, requests_left=-1, backlog=5, max_threads=5):
         """Initialize main loop and set request_handler."""
         self.req_handler = req_handler
         self.fd = fd
@@ -526,16 +526,16 @@
         self._make_socket()
         # how many requests we have left before terminating this process, -1 means infinite lifetime:
         self.requests_left = requests_left
+        # for socket.listen(backlog):
         self.backlog = backlog
+        # how many threads we have at maximum (including the main program = 1. thread)
+        self.max_threads = max_threads
 
-    def run(self):
-        raise NotImplementedError
-
-    def accept_handler(self, conn, addr):
+    def accept_handler(self, conn, addr, inthread=False):
         """Construct Request and run() it."""
         self._check_good_addrs(addr)
         try:
-            req = Request(conn, self.req_handler, self.multi)
+            req = Request(conn, self.req_handler, inthread)
             req.run()
         except SocketErrorOnWrite:
             raise SystemExit
@@ -574,16 +574,8 @@
         if good_addrs is not None and addr not in good_addrs:
             raise RuntimeError("Connection from invalid server!")
 
-class THFCGI(FCGIbase):
-    """Multi-threaded main loop to handle FastCGI Requests."""
-
-    def __init__(self, req_handler, fd=sys.stdin, port=None, requests_left=-1, backlog=5):
-        """Initialize main loop and set request_handler."""
-        self.multi = 1
-        FCGIbase.__init__(self, req_handler, fd, port, requests_left, backlog)
-
     def run(self):
-        """Wait & serve. Calls request_handler in new thread on every request."""
+        """Wait & serve. Calls request_handler on every request."""
         self.sock.listen(self.backlog)
         log("Starting Process")
         running = True
@@ -594,31 +586,15 @@
             elif self.requests_left > 0:
                 self.requests_left -= 1
                 conn, addr = self.sock.accept()
-                log("Accepted connection, starting thread....")
-                t = _threading.Thread(target=self.accept_handler, args=(conn, addr))
-                t.start()
+                threadcount = _threading.activeCount()
+                if threadcount < self.max_threads:
+                    log("Accepted connection, starting thread...")
+                    t = _threading.Thread(target=self.accept_handler, args=(conn, addr, True))
+                    t.start()
+                else:
+                    log("Accepted connection, running in main-thread...")
+                    self.accept_handler(conn, addr, False)
                 log("Active Threads: %d" % _threading.activeCount())
         self.sock.close()
         log("Ending Process")
 
-class unTHFCGI(FCGIbase):
-    """Single-threaded main loop to handle FastCGI Requests."""
-
-    def __init__(self, req_handler, fd=sys.stdin, port=None, requests_left=-1, backlog=5):
-        """Initialize main loop and set request_handler."""
-        self.multi = 0
-        FCGIbase.__init__(self, req_handler, fd, port, requests_left, backlog)
-
-    def run(self):
-        """Wait & serve. Calls request handler for every request (blocking)."""
-        self.sock.listen(self.backlog)
-        running = True
-        while running:
-            if not self.requests_left:
-                running = False
-            elif self.requests_left > 0:
-                self.requests_left -= 1
-                conn, addr = self.sock.accept()
-                self.accept_handler(conn, addr)
-        self.sock.close()
-
--- a/wiki/server/moin.fcg	Sun Aug 13 19:11:12 2006 +0200
+++ b/wiki/server/moin.fcg	Sun Aug 13 19:11:23 2006 +0200
@@ -26,8 +26,14 @@
 ## import os
 ## os.environ['MOIN_DEBUG'] = '1'
 
-# Use threaded version or non-threaded version (default 1)?
-use_threads = 1
+# how many requests shall be handled by a moin fcgi process before it dies:
+max_requests = 1000
+
+# how many threads to use (1 means use only main program, non-threaded)
+max_threads = 5
+
+# backlog, use in socket.listen(backlog) call
+backlog = 5
 
 
 # Code ------------------------------------------------------------------
@@ -37,7 +43,7 @@
 
 # Set threads flag, so other code can use proper locking
 from MoinMoin import config
-config.use_threads = use_threads
+config.use_threads = max_threads > 1
 del config
 
 from MoinMoin.request import FCGI
@@ -48,10 +54,6 @@
     request.run()
 
 if __name__ == '__main__':
-    if use_threads:
-        fcg = thfcgi.THFCGI(handle_request, requests_left=20, backlog=5)
-    else:
-        fcg = thfcgi.unTHFCGI(handle_request, requests_left=20, backlog=5)
-
+    fcg = thfcgi.FCGI(handle_request, requests_left=max_requests, backlog=backlog, max_threads=max_threads)
     fcg.run()