[Checkins] SVN: zc.resumelb/trunk/src/zc/resumelb/ Added HTTP socket timeout to avoid "leaking" connections.
jim
cvs-admin at zope.org
Fri Jun 15 22:11:28 UTC 2012
Log message for revision 126880:
Added HTTP socket timeout to avoid "leaking" connections.
Also changed some backlog/pool tests to be less brittle.
Changed:
U zc.resumelb/trunk/src/zc/resumelb/README.txt
U zc.resumelb/trunk/src/zc/resumelb/tests.py
U zc.resumelb/trunk/src/zc/resumelb/zk.py
U zc.resumelb/trunk/src/zc/resumelb/zk.test
-=-
Modified: zc.resumelb/trunk/src/zc/resumelb/README.txt
===================================================================
--- zc.resumelb/trunk/src/zc/resumelb/README.txt 2012-06-15 22:11:20 UTC (rev 126879)
+++ zc.resumelb/trunk/src/zc/resumelb/README.txt 2012-06-15 22:11:24 UTC (rev 126880)
@@ -242,6 +242,11 @@
Change History
==============
+0.6.2 (2012-06-15)
+------------------
+
+- Fixed: a lack of socket timeout could cause requests to leak.
+
0.6.0 (2012-05-11)
------------------
Modified: zc.resumelb/trunk/src/zc/resumelb/tests.py
===================================================================
--- zc.resumelb/trunk/src/zc/resumelb/tests.py 2012-06-15 22:11:20 UTC (rev 126879)
+++ zc.resumelb/trunk/src/zc/resumelb/tests.py 2012-06-15 22:11:24 UTC (rev 126880)
@@ -247,6 +247,56 @@
"""
+def zk_wsgi_server_output_timeout():
+ r"""
+
+ >>> import zc.resumelb.zk, zc.resumelb.tests, zc.zk
+ >>> zk = zc.zk.ZooKeeper('zookeeper.example.com:2181')
+ >>> zk.import_tree('''
+ ... /test
+ ... /lb
+ ... /providers
+ ... /workers
+ ... /providers
+ ... ''')
+
+ >>> app = zc.resumelb.tests.app()
+ >>> worker = zc.resumelb.zk.worker(
+ ... app, None, address='127.0.0.1:0', run=False,
+ ... zookeeper='zookeeper.example.com:2181', path='/test/lb/workers')
+
+ >>> lb, server = zc.resumelb.zk.lbmain(
+ ... 'zookeeper.example.com:2181 /test/lb -t.2')
+
+ >>> [addr] = map(zc.parse_addr.parse_addr,
+ ... zk.get_children('/test/lb/providers'))
+
+ Now we'll make a request, but not consume output. It should
+ timeout after .2 seconds:
+
+ >>> with mock.patch('sys.stderr'):
+ ... with mock.patch('sys.stdout'):
+ ... sock = gevent.socket.create_connection(addr)
+ ... sock.sendall('GET /gen.html?size=999 HTTP/1.0\r\n\r\n')
+ ... gevent.sleep(1)
+
+ The various output that get's generated in the timeout case is
+ sub-optimal and, hopefully, likely to change, so we won't show it
+ here. The only clue we have that the timeout worked is that the
+ output is less than we expect:
+
+ >>> f = sock.makefile()
+ >>> data = f.read()
+ >>> len(data) < 999*12000
+ True
+
+ >>> worker.stop()
+ >>> server.stop()
+ >>> lb.stop()
+ >>> zk.close()
+
+ """
+
def test_classifier(env):
return "yup, it's a test"
@@ -315,6 +365,6 @@
'zk.test',
setUp=zkSetUp, tearDown=zkTearDown),
doctest.DocTestSuite(
- setUp=setUp, tearDown=zope.testing.setupstack.tearDown),
+ setUp=zkSetUp, tearDown=zope.testing.setupstack.tearDown),
))
Modified: zc.resumelb/trunk/src/zc/resumelb/zk.py
===================================================================
--- zc.resumelb/trunk/src/zc/resumelb/zk.py 2012-06-15 22:11:20 UTC (rev 126879)
+++ zc.resumelb/trunk/src/zc/resumelb/zk.py 2012-06-15 22:11:24 UTC (rev 126880)
@@ -85,6 +85,16 @@
gevent.sleep(.01)
return worker
+class WSGIServer(gevent.pywsgi.WSGIServer):
+
+ def __init__(self, *args, **kw):
+ self.__socket_timeout = kw.pop('socket_timeout')
+ gevent.pywsgi.WSGIServer.__init__(self, *args, **kw)
+
+ def handle(self, socket, address):
+ socket.settimeout(self.__socket_timeout)
+ return gevent.pywsgi.WSGIServer.handle(self, socket, address)
+
def lbmain(args=None, run=True):
"""%prog [options] zookeeper_connection path
@@ -116,6 +126,9 @@
help=("Run a status server for getting pool information. "
"The argument is a unix-domain socket path to listen on."))
parser.add_option(
+ '-t', '--socket-timeout', type='float', default=99.,
+ help=('HTTP socket timeout.'))
+ parser.add_option(
'-L', '--logger-configuration',
help=
"Read logger configuration from the given configuration file path.\n"
@@ -203,9 +216,9 @@
else:
accesslog = None
- server = gevent.pywsgi.WSGIServer(
- addr, lb.handle_wsgi, backlog = options.backlog,
- spawn = spawn, log = accesslog)
+ server = WSGIServer(
+ addr, lb.handle_wsgi, backlog=options.backlog,
+ spawn=spawn, log=accesslog, socket_timeout=options.socket_timeout)
server.start()
registration_data = {}
Modified: zc.resumelb/trunk/src/zc/resumelb/zk.test
===================================================================
--- zc.resumelb/trunk/src/zc/resumelb/zk.test 2012-06-15 22:11:20 UTC (rev 126879)
+++ zc.resumelb/trunk/src/zc/resumelb/zk.test 2012-06-15 22:11:24 UTC (rev 126880)
@@ -202,6 +202,8 @@
Run a status server for getting pool
information. The argument is a unix-domain
socket path to listen on.
+ -t SOCKET_TIMEOUT, --socket-timeout=SOCKET_TIMEOUT
+ HTTP socket timeout.
-L LOGGER_CONFIGURATION, --logger-configuration=LOGGER_CONFIGURATION
Read logger configuration from the given
configuration file path. The configuration
@@ -359,12 +361,18 @@
>>> with mock.patch('ZConfig.configureLoggers') as configureLoggers:
... lb, server = zc.resumelb.zk.lbmain(
... 'zookeeper.example.com:2181 /test/lb'
- ... ' -alocalhost:0 -laccess -b1 -m1'
+ ... ' -alocalhost:0 -laccess -b1 -m2'
... ' --logger-configuration log.conf '
... ' -rzc.resumelb.tests:test_classifier -eoops.html'
... )
... configureLoggers.assert_called_with('loggers')
+ >>> server.backlog
+ 1
+
+ >>> server.pool.size
+ 2
+
>>> lb.disconnect_message
'oops'
@@ -377,12 +385,6 @@
>>> len(lb.pool.workers)
2
- >>> sock = gevent.socket.create_connection(addr)
- >>> sock2 = gevent.socket.create_connection(addr)
- >>> sock3 = gevent.socket.create_connection(addr, .00001)
- Traceback (most recent call last):
- ...
- timeout: timed out
The 3rd collection failed because we said to only accept one
connection at a time and set the backlog to 1.
@@ -395,6 +397,7 @@
Let's do a request.
+ >>> sock = gevent.socket.create_connection(addr)
>>> sock.sendall('''GET /hi.html HTTP/1.0\r
... Host: h1.com\r
... Content-Length: 0\r
@@ -404,7 +407,6 @@
HTTP/1.0 200 OK...
>>> sock.close()
- >>> sock2.close()
We now have access-log records in the access-log handler:
More information about the checkins
mailing list