Skip to content

Commit

Permalink
[arbiter] close sockets on shutdown
Browse files Browse the repository at this point in the history
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 benoitc#922
  • Loading branch information
tilgovi committed Mar 13, 2016
1 parent bbe302e commit de3cacc
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 4 deletions.
2 changes: 2 additions & 0 deletions gunicorn/arbiter.py
Expand Up @@ -334,6 +334,8 @@ def stop(self, graceful=True):
:attr graceful: boolean, If True (the default) workers will be
killed gracefully (ie. trying to wait for the current connection)
"""
for l in self.LISTENERS:
l.close()
self.LISTENERS = []
sig = signal.SIGTERM
if not graceful:
Expand Down
32 changes: 28 additions & 4 deletions tests/test_arbiter.py
Expand Up @@ -5,15 +5,18 @@

import os

try:
import unittest.mock as mock
except ImportError:
import mock

import gunicorn.app.base
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
start the application before spawning worker processes and sets
environmental variable configuration settings.
Dummy application that has an default configuration.
"""

def init(self, parser, opts, args):
Expand All @@ -22,6 +25,27 @@ def init(self, parser, opts, args):
def load(self):
"""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):
"""Set the 'preload_app' and 'raw_env' settings in order to verify their
interaction below.
Expand Down

0 comments on commit de3cacc

Please sign in to comment.