]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Prevent calling waitall() inside a GreenPool's greenthread
authorElena Ezhova <eezhova@mirantis.com>
Thu, 19 Feb 2015 10:34:17 +0000 (13:34 +0300)
committerElena Ezhova <eezhova@mirantis.com>
Tue, 10 Mar 2015 10:43:24 +0000 (13:43 +0300)
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
neutron/tests/unit/test_metadata_agent.py
neutron/tests/unit/test_wsgi.py
neutron/wsgi.py

index 390092d0bd00e367242214e27ffd9b95cffd9e7f..21ecea3e842d10b80ad860e8f8b3b75c585587cd 100644 (file)
@@ -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))
 
index 4e5fac39fdf9f4366187a94ae8f212d14b565a96..b85ce2d6054718282f189fce6f02cd8f3d14c010 100644 (file)
@@ -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))
 
index e936289cb9385bfa92ab9b50cc4d31496283574d..38b407071d0f2b91d0b7998b46dc2897c8f2581e 100644 (file)
@@ -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):
index 881cfb84eefa77d609cdcffdb348a06762efff1b..d99cdaafc41c2669cd706ed9c57a7652a4251990 100644 (file)
@@ -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)