From fb909088d911c94a465fce150dda0586fcd746c1 Mon Sep 17 00:00:00 2001 From: Dave Shawley Date: Sun, 28 Jan 2018 14:32:41 -0500 Subject: [PATCH] Enable reuse_port option to HTTPServer.bind. This makes solutions that restart the process (e.g., envconsul) work properly. Without port reuse, you will get a very unpleasant "port already in use" when the service restarts. This requires Tornado >= 4.4 --- docs/history.rst | 4 ++++ sprockets/http/runner.py | 8 +++++++- tests.py | 22 +++++++++++++++++++--- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/docs/history.rst b/docs/history.rst index 5e2d300..1309acd 100644 --- a/docs/history.rst +++ b/docs/history.rst @@ -3,6 +3,10 @@ Release History =============== +`Next Release`_ +--------------- +- Enable port reuse for Tornado versions newer than 4.3. + `1.4.2`_ (25 Jan 2018) --------------------- - Allow max_body_size and max_buffer_size to be specified on the http server. diff --git a/sprockets/http/runner.py b/sprockets/http/runner.py index 6121eba..3443186 100644 --- a/sprockets/http/runner.py +++ b/sprockets/http/runner.py @@ -12,6 +12,7 @@ import signal import sys from tornado import httpserver, ioloop +import tornado import sprockets.http.app @@ -90,7 +91,12 @@ class Runner(object): self.server.listen(port_number) else: self.logger.info('starting processes on port %d', port_number) - self.server.bind(port_number) + if tornado.version_info >= (4, 4): + self.server.bind(port_number, reuse_port=True) + else: + self.logger.warning('port reuse disabled, please upgrade to' + 'at least Tornado 4.4') + self.server.bind(port_number) self.server.start(number_of_procs) def stop_server(self): diff --git a/tests.py b/tests.py index 0fa79b4..bbb9263 100644 --- a/tests.py +++ b/tests.py @@ -14,7 +14,8 @@ except ImportError: import mock open_name = '__builtin__.open' -from tornado import concurrent, httputil, ioloop, testing, web +from tornado import concurrent, httpserver, httputil, ioloop, testing, web +import tornado import sprockets.http.mixins import sprockets.http.runner @@ -383,7 +384,7 @@ class RunnerTests(MockHelper, unittest.TestCase): ioloop_module = self.start_mock('sprockets.http.runner.ioloop') ioloop_module.IOLoop.instance.return_value = self.io_loop - self.http_server = mock.Mock() + self.http_server = mock.Mock(spec=httpserver.HTTPServer) self.httpserver_module = \ self.start_mock('sprockets.http.runner.httpserver') self.httpserver_module.HTTPServer.return_value = self.http_server @@ -402,9 +403,24 @@ class RunnerTests(MockHelper, unittest.TestCase): def test_that_production_run_starts_in_multiprocess_mode(self): runner = sprockets.http.runner.Runner(self.application) runner.run(8000) - self.http_server.bind.assert_called_once_with(8000) + + self.assertTrue(self.http_server.bind.called) + args, kwargs = self.http_server.bind.call_args_list[0] + self.assertEqual(args, (8000, )) + self.http_server.start.assert_called_once_with(0) + @unittest.skipUnless(tornado.version_info >= (4, 4), + 'port reuse requries newer tornado') + def test_that_production_enables_reuse_port(self): + runner = sprockets.http.runner.Runner(self.application) + runner.run(8000) + + self.assertTrue(self.http_server.bind.called) + args, kwargs = self.http_server.bind.call_args_list[0] + self.assertEqual(args, (8000, )) + self.assertEqual(kwargs['reuse_port'], True) + def test_that_debug_run_starts_in_singleprocess_mode(self): self.application.settings['debug'] = True runner = sprockets.http.runner.Runner(self.application)