From f9b2791735863b58171ee8be46c47ef3ed2c5edd Mon Sep 17 00:00:00 2001 From: Elena Ezhova Date: Thu, 19 Feb 2015 13:34:17 +0300 Subject: [PATCH] Prevent calling waitall() inside a GreenPool's greenthread When neutron-server is running with several api workers sending it a termination signal (SIGTERM, SIGHUP or SIGINT) leads to waitall() being called inside a GreenPool's greenthread. The reason is that a wsgi server is started in a green thread from the same green pool that is passed to the server itself to be used for spawning client green threads. To avoid it, it is reasonable to use different pools for spawning a wsgi server and for its internal usage. This is also the case for metadata agent running with several metadata workers. Change-Id: I38174396f06fcb29ac0776534ac6494dabb00df6 Closes-Bug: #1423250 --- neutron/agent/metadata/agent.py | 2 +- neutron/tests/unit/test_metadata_agent.py | 2 +- neutron/tests/unit/test_wsgi.py | 15 +++++++++++++++ neutron/wsgi.py | 9 ++++++--- 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/neutron/agent/metadata/agent.py b/neutron/agent/metadata/agent.py index 390092d0b..21ecea3e8 100644 --- a/neutron/agent/metadata/agent.py +++ b/neutron/agent/metadata/agent.py @@ -292,7 +292,7 @@ class UnixDomainWSGIServer(wsgi.Server): logger = logging.getLogger('eventlet.wsgi.server') eventlet.wsgi.server(socket, application, - custom_pool=self.pool, + max_size=self.num_threads, protocol=UnixDomainHttpProtocol, log=logging.WritableLogger(logger)) diff --git a/neutron/tests/unit/test_metadata_agent.py b/neutron/tests/unit/test_metadata_agent.py index 4e5fac39f..b85ce2d60 100644 --- a/neutron/tests/unit/test_metadata_agent.py +++ b/neutron/tests/unit/test_metadata_agent.py @@ -549,7 +549,7 @@ class TestUnixDomainWSGIServer(base.BaseTestCase): 'app', protocol=agent.UnixDomainHttpProtocol, log=mock.ANY, - custom_pool=self.server.pool + max_size=self.server.num_threads ) self.assertTrue(len(logging.mock_calls)) diff --git a/neutron/tests/unit/test_wsgi.py b/neutron/tests/unit/test_wsgi.py index e936289cb..38b407071 100644 --- a/neutron/tests/unit/test_wsgi.py +++ b/neutron/tests/unit/test_wsgi.py @@ -138,6 +138,21 @@ class TestWSGIServer(base.BaseTestCase): server.stop() + @mock.patch.object(wsgi, 'eventlet') + @mock.patch.object(wsgi, 'logging') + def test__run(self, logging_mock, eventlet_mock): + server = wsgi.Server('test') + server._run("app", "socket") + eventlet_mock.wsgi.server.assert_called_once_with( + 'socket', + 'app', + max_size=server.num_threads, + log=mock.ANY, + keepalive=CONF.wsgi_keep_alive, + socket_timeout=server.client_socket_timeout + ) + self.assertTrue(len(logging_mock.mock_calls)) + class SerializerTest(base.BaseTestCase): def test_serialize_unknown_content_type(self): diff --git a/neutron/wsgi.py b/neutron/wsgi.py index 881cfb84e..d99cdaafc 100644 --- a/neutron/wsgi.py +++ b/neutron/wsgi.py @@ -118,10 +118,12 @@ class WorkerService(object): class Server(object): """Server class to manage multiple WSGI sockets and applications.""" - def __init__(self, name, threads=1000): + def __init__(self, name, num_threads=1000): # Raise the default from 8192 to accommodate large tokens eventlet.wsgi.MAX_HEADER_LINE = CONF.max_header_line - self.pool = eventlet.GreenPool(threads) + self.num_threads = num_threads + # Pool for a greenthread in which wsgi server will be running + self.pool = eventlet.GreenPool(1) self.name = name self._server = None # A value of 0 is converted to None because None is what causes the @@ -254,7 +256,8 @@ class Server(object): def _run(self, application, socket): """Start a WSGI server in a new green thread.""" - eventlet.wsgi.server(socket, application, custom_pool=self.pool, + eventlet.wsgi.server(socket, application, + max_size=self.num_threads, log=logging.WritableLogger(LOG), keepalive=CONF.wsgi_keep_alive, socket_timeout=self.client_socket_timeout) -- 2.45.2