Proper way to shutdown asyncio tasks

后端 未结 2 1636
不知归路
不知归路 2021-02-04 01:00

I am writing a tool which connects to X number of UNIX sockets, sends a command and saves the output in the local file-system. It runs this every X seconds. In order to perform

2条回答
  •  不思量自难忘°
    2021-02-04 01:20

    The cancellation is not immediate and requires running ioloop to be resolved with exception CancelledError. Remove ioloop.stop from shutdown and handle exception in supervisor, to make things work. Below simplified example.

    Important is, however you can cancel Task, it only stops watching/waiting for end/results and loop won't handle further events for it. But the underneath request/pipe will not be stopped.

    Simplified example:

    import asyncio
    import functools
    import logging
    import signal
    import sys
    from concurrent.futures import CancelledError
    
    
    def shutdown(loop):
        logging.info('received stop signal, cancelling tasks...')
        for task in asyncio.Task.all_tasks():
            task.cancel()
        logging.info('bye, exiting in a minute...')    
    
    
    @asyncio.coroutine
    def get(i):
        logging.info('sleep for %d', i)
        yield from asyncio.sleep(i)    
    
    
    @asyncio.coroutine
    def pull_stats():
        coroutines = [get(i) for i in range(10,20)]
        status = yield from asyncio.gather(*coroutines)
    
    
    def supervisor(loop):
        try:
            while True:
                result = loop.run_until_complete(pull_stats())
        except CancelledError:
            logging.info('CancelledError')
        loop.close()
        sys.exit(1)
    
    
    def main():
        logging.getLogger().setLevel(logging.INFO)
        loop = asyncio.get_event_loop()
        loop.add_signal_handler(signal.SIGHUP, functools.partial(shutdown, loop))
        loop.add_signal_handler(signal.SIGTERM, functools.partial(shutdown, loop))
        supervisor(loop)
    
    
    if __name__ == '__main__':
        main()
    

    Note, that if you cancel only gather's Future, all children will be set as cancelled as well.

    And the sleep thing

    Any receipt of a signal or interrupt causes the program to resume execution. So when the process receive SIGTERM and handler is set, python allows you to handle it, to do this thread is resumed and sighandler is called. Due to implementation of ioloop and its signal handling, it keeps running after wake.

提交回复
热议问题