Based on this code, I'm trying to catch SIGINT and SIGTERM. It works perfectly for SIGINT: I see it enter the signal handler, then my tasks do their cleanup before the whole program exits. On SIGTERM, though, the program simply exits immediately. My code is a bit of a hybrid of the two examples from the link above, as much of the original doesn't work under python 3.12: async def signal_handler(sig, loop): """ Exit cleanly on SIGTERM ("docker stop"), SIGINT (^C when interactive) """ print('caught {0}'.format(sig.name)) tasks = [task for task in asyncio.all_tasks() if task is not asyncio.current_task()] list(map(lambda task: task.cancel(), tasks)) results = await asyncio.gather(*tasks, return_exceptions=True) print('finished awaiting cancelled tasks, results: {0}'.format(results)) loop.stop() if __name__ == "__main__": loop = asyncio.new_event_loop() asyncio.ensure_future(task1(), loop=loop) asyncio.ensure_future(task2(), loop=loop) loop.add_signal_handler(signal.SIGTERM, functools.partial(asyncio.ensure_future, signal_handler(signal.SIGTERM, loop))) loop.add_signal_handler(signal.SIGINT, functools.partial(asyncio.ensure_future, signal_handler(signal.SIGINT, loop))) try: loop.run_forever() finally: loop.close() task1 can terminate immediately, but task2 has cleanup code that is clearly being executed after SIGINT, but not after SIGTERM Continue reading...