[arbiter] close sockets on shutdown

Close all the listeners when the arbiter shuts down. By doing so,
workers can close the socket at the beginning of a graceful shut
down thereby informing the operating system that the socket can
be cleaned up. With this change, graceful exits with such workers
will refuse new connections while draining, allowing load balancers
to respond more quickly and avoiding leaving connections dangling
in the listen backlog, unaccepted.

Ref #922
This commit is contained in:
Randall Leeds 2016-03-13 16:18:45 -07:00
parent e05941cec2
commit 39cecbc8e9
2 changed files with 30 additions and 4 deletions

View File

@ -334,6 +334,8 @@ class Arbiter(object):
:attr graceful: boolean, If True (the default) workers will be :attr graceful: boolean, If True (the default) workers will be
killed gracefully (ie. trying to wait for the current connection) killed gracefully (ie. trying to wait for the current connection)
""" """
for l in self.LISTENERS:
l.close()
self.LISTENERS = [] self.LISTENERS = []
sig = signal.SIGTERM sig = signal.SIGTERM
if not graceful: if not graceful:

View File

@ -5,15 +5,18 @@
import os import os
try:
import unittest.mock as mock
except ImportError:
import mock
import gunicorn.app.base import gunicorn.app.base
import gunicorn.arbiter import gunicorn.arbiter
class PreloadedAppWithEnvSettings(gunicorn.app.base.BaseApplication): class DummyApplication(gunicorn.app.base.BaseApplication):
""" """
Simple application that makes use of the 'preload' feature to Dummy application that has an default configuration.
start the application before spawning worker processes and sets
environmental variable configuration settings.
""" """
def init(self, parser, opts, args): def init(self, parser, opts, args):
@ -22,6 +25,27 @@ class PreloadedAppWithEnvSettings(gunicorn.app.base.BaseApplication):
def load(self): def load(self):
"""No-op""" """No-op"""
def load_config(self):
"""No-op"""
def test_arbiter_shutdown_closes_listeners():
arbiter = gunicorn.arbiter.Arbiter(DummyApplication())
listener1 = mock.Mock()
listener2 = mock.Mock()
arbiter.LISTENERS = [listener1, listener2]
arbiter.stop()
listener1.close.assert_called_with()
listener2.close.assert_called_with()
class PreloadedAppWithEnvSettings(DummyApplication):
"""
Simple application that makes use of the 'preload' feature to
start the application before spawning worker processes and sets
environmental variable configuration settings.
"""
def load_config(self): def load_config(self):
"""Set the 'preload_app' and 'raw_env' settings in order to verify their """Set the 'preload_app' and 'raw_env' settings in order to verify their
interaction below. interaction below.