asyncio - How can coroutines be used in signal handlers?

Jinnog picture Jinnog · Apr 26, 2014 · Viewed 8.4k times · Source

I am developing an application that uses asyncio from python3.4 for networking. When this application shuts down cleanly, a node needs to "disconnect" from the hub. This disconnect is an active process that requires a network connection so the loop needs to wait for this to complete before shutting down.

My issue is that using a coroutine as a signal handler will result in the application not shutting down. Please consider the following example:

import asyncio
import functools
import os
import signal

@asyncio.coroutine
def ask_exit(signame):
    print("got signal %s: exit" % signame)
    yield from asyncio.sleep(10.0)
    loop.stop()

loop = asyncio.get_event_loop()
for signame in ('SIGINT', 'SIGTERM'):
    loop.add_signal_handler(getattr(signal, signame),
                                        functools.partial(ask_exit, signame))

print("Event loop running forever, press CTRL+c to interrupt.")
print("pid %s: send SIGINT or SIGTERM to exit." % os.getpid())
loop.run_forever()

If you run this example and then press Ctrl+C, nothing will happen. The question is, how do I make this behavior happen with siganls and coroutines?

Answer

svs picture svs · Feb 10, 2017

Syntax for python >=3.5

loop = asyncio.get_event_loop()
for signame in ('SIGINT', 'SIGTERM'):
    loop.add_signal_handler(getattr(signal, signame),
                            lambda: asyncio.ensure_future(ask_exit(signame)))