Skip to content

Commit

Permalink
daemon: Switch signal handling to event loop
Browse files Browse the repository at this point in the history
Now that we're using asyncio we need to use its signal handling
functions so we don't confuse it. One symptom is that server shutdown
will hang indefinitely if triggered from a signal.signal signal handler.

So we switch to asyncio.loop.add_signal_handler() which is mostly a
drop-in replacement. Handler routines are normal functions and cannot
even be coroutines, so no problem there. Signal handlers have no default
or standard parameters any more so we need to pass the signal number
explicitly if we want to be able to distringuish them.

One potential area of concern is registering the signal handlers with
the correct event loop. Normally we'd pass the one we used for signal
handlers explicitly to all other components using asyncio.
Unfortunately, sanic does not allow that in the case of
sanic.app.create_server(). But fortunately, it calls
asyncio.get_event_loop() itself which yields the same global event loop
as long as no-one goes around and starts creating new loops.

This even works with sanic's behaviour up to and including version
21.9.3 of unconditionally switching the default asyncio event loop
implementation to uvloop as it seems to happen early enough (on import
sanic in server) so that our first call to get_event_loop() in the daemo
also yields the uvloop loop eventually employed by sanic to create the
server.

So we now silently use uvloop with sanic up to and including 21.9.3 and
standard asyncio with sanic 22.12.0 and later. Incidentally, the whole
isssue became apparent only because with 22.12.0 shutdown would no
longer work because python stdlib asyncio doesn't react well to
signal.signal handling signals while with uvloop it works fine.
  • Loading branch information
michaelweiser committed Mar 9, 2022
1 parent 94486d6 commit 9051be9
Showing 1 changed file with 9 additions and 6 deletions.
15 changes: 9 additions & 6 deletions peekaboo/daemon.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
""" The main peekaboo module, starting up and managing all the various
components. """

import asyncio
import errno
import gettext
import os
Expand All @@ -50,15 +51,16 @@

logger = logging.getLogger(__name__)


class SignalHandler:
""" Signal handler. """
def __init__(self):
def __init__(self, loop):
""" register custom signal handler """
self.listeners = []

signal.signal(signal.SIGINT, self.signal_handler)
signal.signal(signal.SIGTERM, self.signal_handler)
loop.add_signal_handler(
signal.SIGINT, self.signal_handler, signal.SIGINT)
loop.add_signal_handler(
signal.SIGTERM, self.signal_handler, signal.SIGTERM)

self.shutdown_requested = False

Expand All @@ -69,7 +71,7 @@ def register_listener(self, listener):
"""
self.listeners.append(listener)

def signal_handler(self, sig, _):
def signal_handler(self, sig):
""" catch signal and call appropriate methods in registered listener
classes """
if sig in [signal.SIGINT, signal.SIGTERM]:
Expand Down Expand Up @@ -313,7 +315,8 @@ def run():
"interval to %d seconds.",
cldup_check_interval)

sig_handler = SignalHandler()
loop = asyncio.get_event_loop()
sig_handler = SignalHandler(loop)

# read in the analyzer and ruleset configuration and start the job queue
try:
Expand Down

0 comments on commit 9051be9

Please sign in to comment.