Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When to use loop.add_signal_handler?

I noticed the asyncio library has a loop.add_signal_handler(signum, callback, *args) method.

So far I have just been catching unix signals in the main file using the signals module in with my asynchronous code like this:

signal.signal(signal.SIGHUP, callback)

async def main():
    ...

Is that an oversight on my part?

like image 207
sphere Avatar asked Dec 10 '18 11:12

sphere


1 Answers

The add_signal_handler documentation is sparse1, but looking at the source, it appears that the main added value compared to signal.signal is that add_signal_handler will ensure that the signal wakes up the event loop and allow the loop to invoke the signal handler along with other queued callbacks and runnable coroutines.

So far I have just been catching unix signals in the main file using the signals module [...] Is that an oversight on my part?

That depends on what the signal handler is doing. Printing a message or updating a global is fine, but if it is invoking anything in any way related to asyncio, it's most likely an oversight. A signal can be delivered at (almost) any time, including during execution of an asyncio callback, a coroutine, or even during asyncio's own bookkeeping.

For example, the implementation of asyncio.Queue freely assumes that the access to the queue is single-threaded and non-reentrant. A signal handler adding something to a queue using q.put_nowait() would be disastrous if it interrupted an on-going invocation of q.put_nowait() on the same queue. Similar to typical race conditions experienced in multi-threaded code, an interruption in the middle of assignment to _unfinished_tasks might well cause it to get incremented only once instead of twice (once for each put_nowait).

Asyncio code is designed for cooperative multi-tasking, where the points where a function may suspend defined are clearly denoted by the await and related keywords. The add_signal_handler function ensures that your signal handler gets invoked at such a point, and that you're free to implement it as you'd implement any other asyncio callback.


1 When this answer was originally written, the add_signal_handler documentation was briefer than today and didn't cover the difference to signal.signal at all. This question prompted it getting expanded in the meantime.
like image 126
user4815162342 Avatar answered Oct 19 '22 09:10

user4815162342