def factory_trigger()

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)