def add_runner()

in src/asfquart/base.py [0:0]


    def add_runner(self, func, name=None):
        "Add a long-running task, with cancellation/cleanup."

        # NOTES:
        #
        # We take advantage of the WHILE_SERVING mechanism that uses a
        # generator to manage the lifecycle of a task. We create/schedule
        # a task when the app starts up, then yield back to the framework.
        # Control returns when the app is shutting down, and we can cleanly
        # cancel the long-running task.
        #
        # Contrast this with APP.background_tasks. Each task placed into
        # that set must monitor APP.shutdown_event to know when the task
        # should exit (or an external mechanism observing that event must
        # cancel the task). The coordination becomes more difficult, and
        # must be handled by the application logic. The WHILE_SERVING
        # mechanism used here places no demands upon the caller to manage
        # the lifecycle of the long-running task.
        #
        # Further note: should a task be placed into APP.background_tasks,
        # it will be waited on to exit at shutdown time. If the task is
        # not watching APP.shutdown_event, and does not complete, finish,
        # or cancel within a timeout period (default is 5 seconds), then
        # that background task is canceled. That is an unstructured
        # completion/cancellation mechanism and introduces a delay during
        # the shutdown process.

        @self.while_serving
        async def perform_runner():
            ctask = utils.CancellableTask(func(), name=name)
            #print('RUNNER STARTED:', ctask.task)

            yield  # back to serving

            #print('RUNNER STOPPING:', ctask.task)
            ctask.cancel()