Make shutdown timings configurable.

This commit is contained in:
Dave Shawley 2019-09-01 09:21:20 -04:00
parent eab16f5f2a
commit 7991f99807
4 changed files with 17 additions and 7 deletions

View file

@ -5,6 +5,7 @@ Release History
`Next Release`_ `Next Release`_
--------------- ---------------
- Make shutdown timings configurable.
`2.0.1`_ (5 Mar 2019) `2.0.1`_ (5 Mar 2019)
---------------------- ----------------------

View file

@ -8,11 +8,12 @@ from tornado import concurrent, web
class _ShutdownHandler: class _ShutdownHandler:
"""Keeps track of the application state during shutdown.""" """Keeps track of the application state during shutdown."""
def __init__(self, io_loop): def __init__(self, io_loop, shutdown_limit, wait_timeout):
self.io_loop = io_loop self.io_loop = io_loop
self.logger = logging.getLogger(self.__class__.__name__) self.logger = logging.getLogger(self.__class__.__name__)
self.pending_callbacks = 0 self.pending_callbacks = 0
self.shutdown_limit = 5 self.shutdown_limit = shutdown_limit
self.wait_timeout = wait_timeout
self.__deadline = None self.__deadline = None
def add_future(self, future): def add_future(self, future):
@ -42,7 +43,7 @@ class _ShutdownHandler:
def _maybe_stop(self): def _maybe_stop(self):
now = self.io_loop.time() now = self.io_loop.time()
if now < self.__deadline and asyncio.Task.all_tasks(): if now < self.__deadline and asyncio.Task.all_tasks():
self.io_loop.add_timeout(now + 1, self._maybe_stop) self.io_loop.add_timeout(now + self.wait_timeout, self._maybe_stop)
else: else:
self.io_loop.stop() self.io_loop.stop()
self.logger.info('stopped IOLoop') self.logger.info('stopped IOLoop')
@ -103,20 +104,24 @@ class CallbackManager:
for callback in self.on_start_callbacks: for callback in self.on_start_callbacks:
io_loop.spawn_callback(callback, self.tornado_application, io_loop) io_loop.spawn_callback(callback, self.tornado_application, io_loop)
def stop(self, io_loop): def stop(self, io_loop, shutdown_limit=5.0, wait_timeout=1.0):
""" """
Asynchronously stop the application. Asynchronously stop the application.
:param tornado.ioloop.IOLoop io_loop: loop to run until all :param tornado.ioloop.IOLoop io_loop: loop to run until all
callbacks, timeouts, and queued calls are complete callbacks, timeouts, and queued calls are complete
:param float shutdown_limit: maximum number of seconds to wait
before terminating
:param float wait_timeout: number of seconds to wait between checks
for pending callbacks & timers
Call this method to start the application shutdown process. Call this method to start the application shutdown process.
The IOLoop will be stopped once the application is completely The IOLoop will be stopped once the application is completely
shut down. shut down or after `shutdown_limit` seconds.
""" """
running_async = False running_async = False
shutdown = _ShutdownHandler(io_loop) shutdown = _ShutdownHandler(io_loop, shutdown_limit, wait_timeout)
for callback in self.on_shutdown_callbacks: for callback in self.on_shutdown_callbacks:
try: try:
maybe_future = callback(self.tornado_application) maybe_future = callback(self.tornado_application)

View file

@ -55,6 +55,8 @@ class Runner:
app, before_run, on_start, shutdown) app, before_run, on_start, shutdown)
self.logger = logging.getLogger('Runner') self.logger = logging.getLogger('Runner')
self.server = None self.server = None
self.shutdown_limit = 5.0
self.wait_timeout = 1.0
def start_server(self, port_number, number_of_procs=0): def start_server(self, port_number, number_of_procs=0):
""" """
@ -142,7 +144,8 @@ class Runner:
self.stop_server() self.stop_server()
# Start the application shutdown process # Start the application shutdown process
self.application.stop(ioloop.IOLoop.instance()) self.application.stop(ioloop.IOLoop.instance(), self.shutdown_limit,
self.wait_timeout)
class RunCommand(cmd.Command): class RunCommand(cmd.Command):

View file

@ -448,6 +448,7 @@ class RunnerTests(MockHelper, unittest.TestCase):
self.io_loop._timeouts = [mock.Mock()] self.io_loop._timeouts = [mock.Mock()]
runner = sprockets.http.runner.Runner(self.application) runner = sprockets.http.runner.Runner(self.application)
runner.shutdown_limit = 0.25 runner.shutdown_limit = 0.25
runner.wait_timeout = 0.05
runner.run(8000) runner.run(8000)
runner._shutdown() runner._shutdown()
self.io_loop.stop.assert_called_once_with() self.io_loop.stop.assert_called_once_with()