wsgi: Add keepalive_timeout option

Clients sometimes hold open connections "just in case" they might later
pipeline requests. This can cause issues for proxies, especially if
operators restrict max_clients in an effort to improve response times
for the requests that *do* get serviced.

Add a new keepalive_timeout option to give proxies a way to drop these
established-but-idle connections without impacting active connections
(as may happen when reducing client_timeout). Note that this requires
eventlet 0.33.4 or later.

Change-Id: Ib5bb84fa3f8a4b9c062d58c8d3689e7030d9feb3
This commit is contained in:
Tim Burke 2023-02-13 21:46:40 -08:00
parent 4b6f54d063
commit 469c38e9fb
3 changed files with 14 additions and 0 deletions

View File

@ -85,8 +85,14 @@ bind_port = 8080
# CORS documentation).
# cors_expose_headers =
#
# General timeout when sending to or receiving from clients.
# client_timeout = 60.0
#
# Timeout to use when looking for pipelined requests. Set to zero to disable
# request pipelining. Defaults to client_timeout. Requires eventlet>=0.33.4;
# with earlier eventlet, any non-zero value is treated as client_timeout.
# keepalive_timeout =
#
# Note: enabling evenlet_debug might reveal sensitive information, for example
# signatures for temp urls
# eventlet_debug = false

View File

@ -434,6 +434,9 @@ def run_server(conf, logger, sock, global_conf=None, ready_callback=None,
# header; "Etag" just won't do).
'capitalize_response_headers': False,
}
if conf.get('keepalive_timeout'):
server_kwargs['keepalive'] = float(conf['keepalive_timeout']) or False
if ready_callback:
ready_callback()
# Yes, eventlet, we know -- we have to support bad clients, though

View File

@ -496,6 +496,7 @@ class TestWSGI(unittest.TestCase):
config = """
[DEFAULT]
client_timeout = 30
keepalive_timeout = 10
max_clients = 1000
swift_dir = TEMPDIR
@ -535,6 +536,7 @@ class TestWSGI(unittest.TestCase):
self.assertTrue('custom_pool' in kwargs)
self.assertEqual(1000, kwargs['custom_pool'].size)
self.assertEqual(30, kwargs['socket_timeout'])
self.assertEqual(10, kwargs['keepalive'])
proto_class = kwargs['protocol']
self.assertEqual(proto_class, wsgi.SwiftHttpProtocol)
@ -585,6 +587,7 @@ class TestWSGI(unittest.TestCase):
self.assertTrue('custom_pool' in kwargs)
self.assertEqual(10, kwargs['custom_pool'].size)
self.assertEqual(2.5, kwargs['socket_timeout'])
self.assertNotIn('keepalive', kwargs) # eventlet defaults to True
proto_class = kwargs['protocol']
self.assertEqual(proto_class, wsgi.SwiftHttpProxiedProtocol)
@ -594,6 +597,7 @@ class TestWSGI(unittest.TestCase):
config = """
[DEFAULT]
swift_dir = TEMPDIR
keepalive_timeout = 0
[pipeline:main]
pipeline = proxy-server
@ -623,6 +627,7 @@ class TestWSGI(unittest.TestCase):
self.assertTrue('protocol' in kwargs)
self.assertEqual('HTTP/1.0',
kwargs['protocol'].default_request_version)
self.assertIs(False, kwargs['keepalive'])
def test_run_server_conf_dir(self):
config_dir = {