in src/asfquart/base.py [0:0]
def factory_trigger(self, loop, extra_files=frozenset()):
"""Factory for an AWAITABLE that handles special exceptions.
The LOOP normally ignores all signals. This method will make the
loop catch SIGTERM/SIGINT, then set an Event to raise an exception
for a clean exit.
This will also observe files for changes, and signal the loop
to reload the application.
"""
# Note: Quart.run() allows for optional signal handlers. We do not.
shutdown_event = asyncio.Event()
def _shutdown_handler(*_) -> None:
shutdown_event.set()
loop.add_signal_handler(signal.SIGTERM, _shutdown_handler)
loop.add_signal_handler(signal.SIGINT, _shutdown_handler)
async def shutdown_wait():
"Log a nice message when we're signalled to shut down."
await shutdown_event.wait()
LOGGER.info('SHUTDOWN: Performing graceful exit...')
gathered.cancel()
raise hypercorn.utils.ShutdownError()
restart_event = asyncio.Event()
def _restart_handler(*_) -> None:
restart_event.set()
loop.add_signal_handler(signal.SIGUSR2, _restart_handler)
async def restart_wait():
"Log a nice message when we're signalled to restart."
await restart_event.wait()
LOGGER.info('RESTART: Performing process restart...')
gathered.cancel()
raise quart.utils.MustReloadError()
# Normally, for the SHUTDOWN_TRIGGER, it simply completes and
# returns (eg. waiting on an event) as it gets wrapped into
# hypercorn.utils.raise_shutdown() to raise ShutdownError.
#
# We are gathering three tasks, each running forever until its
# condition raises an exception.
#
# .watch() will raise MustReloadError
# shutdown_wait() will raise ShutdownError
# restart_wait() will raise MustReloadError
t1 = loop.create_task(self.watch(extra_files),
name=f'Watch:{self.app_id}')
t2 = loop.create_task(shutdown_wait(),
name=f'Shutdown:{self.app_id}')
t3 = loop.create_task(restart_wait(),
name=f'Restart:{self.app_id}')
aw = asyncio.gather(t1, t2, t3)
gathered = utils.CancellableTask(aw, loop=loop,
name=f'Trigger:{self.app_id}')
async def await_gathered():
await gathered.task
return await_gathered # factory to create an awaitable (coro)