Merge pull request #1437 from jodal/fix/1435-stop-on-sigterm

Stop GLib mainloop on SIGTERM
This commit is contained in:
Stein Magnus Jodal 2016-02-10 21:59:33 +01:00
commit be568b769f
3 changed files with 22 additions and 12 deletions

View File

@ -27,7 +27,7 @@ def main():
log.bootstrap_delayed_logging() log.bootstrap_delayed_logging()
logger.info('Starting Mopidy %s', versioning.get_version()) logger.info('Starting Mopidy %s', versioning.get_version())
signal.signal(signal.SIGTERM, process.exit_handler) signal.signal(signal.SIGTERM, process.sigterm_handler)
# Windows does not have signal.SIGUSR1 # Windows does not have signal.SIGUSR1
if hasattr(signal, 'SIGUSR1'): if hasattr(signal, 'SIGUSR1'):
signal.signal(signal.SIGUSR1, pykka.debug.log_thread_tracebacks) signal.signal(signal.SIGUSR1, pykka.debug.log_thread_tracebacks)

View File

@ -5,6 +5,7 @@ import collections
import contextlib import contextlib
import logging import logging
import os import os
import signal
import sys import sys
import pykka import pykka
@ -13,7 +14,7 @@ from mopidy import config as config_lib, exceptions
from mopidy.audio import Audio from mopidy.audio import Audio
from mopidy.core import Core from mopidy.core import Core
from mopidy.internal import deps, process, timer, versioning from mopidy.internal import deps, process, timer, versioning
from mopidy.internal.gi import GLib, GObject from mopidy.internal.gi import GLib
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -283,7 +284,13 @@ class RootCommand(Command):
help='`section/key=value` values to override config options') help='`section/key=value` values to override config options')
def run(self, args, config): def run(self, args, config):
loop = GObject.MainLoop() def on_sigterm(loop):
logger.info('GLib mainloop got SIGTERM. Exiting...')
loop.quit()
loop = GLib.MainLoop()
GLib.unix_signal_add(
GLib.PRIORITY_DEFAULT, signal.SIGTERM, on_sigterm, loop)
mixer_class = self.get_mixer_class(config, args.registry['mixer']) mixer_class = self.get_mixer_class(config, args.registry['mixer'])
backend_classes = args.registry['backend'] backend_classes = args.registry['backend']
@ -300,6 +307,7 @@ class RootCommand(Command):
backends = self.start_backends(config, backend_classes, audio) backends = self.start_backends(config, backend_classes, audio)
core = self.start_core(config, mixer, backends, audio) core = self.start_core(config, mixer, backends, audio)
self.start_frontends(config, frontend_classes, core) self.start_frontends(config, frontend_classes, core)
logger.info('Starting GLib mainloop')
loop.run() loop.run()
except (exceptions.BackendError, except (exceptions.BackendError,
exceptions.FrontendError, exceptions.FrontendError,

View File

@ -1,7 +1,6 @@
from __future__ import absolute_import, unicode_literals from __future__ import absolute_import, unicode_literals
import logging import logging
import signal
import threading import threading
import pykka import pykka
@ -12,20 +11,23 @@ from mopidy.compat import thread
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
SIGNALS = dict(
(k, v) for v, k in signal.__dict__.items()
if v.startswith('SIG') and not v.startswith('SIG_'))
def exit_process(): def exit_process():
logger.debug('Interrupting main...') logger.debug('Interrupting main...')
thread.interrupt_main() thread.interrupt_main()
logger.debug('Interrupted main') logger.debug('Interrupted main')
def exit_handler(signum, frame): def sigterm_handler(signum, frame):
"""A :mod:`signal` handler which will exit the program on signal.""" """A :mod:`signal` handler which will exit the program on signal.
logger.info('Got %s signal', SIGNALS[signum])
This function is not called when the process' main thread is running a GLib
mainloop. In that case, the GLib mainloop must listen for SIGTERM signals
and quit itself.
For Mopidy subcommands that does not run the GLib mainloop, this handler
ensures a proper shutdown of the process on SIGTERM.
"""
logger.info('Got SIGTERM signal. Exiting...')
exit_process() exit_process()