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
This commit is contained in:
Elena Ezhova 2015-02-19 13:34:17 +03:00
parent 7cd356964c
commit f9b2791735
4 changed files with 23 additions and 5 deletions

View 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))

View 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))

View 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):

View 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)