From 4873012914a7f89d198801f8a7966c1e825eb60c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Ma=C5=9Blanka?= <piotr.maslanka@henrietta.com.pl> Date: Mon, 30 Dec 2019 20:37:51 +0100 Subject: [PATCH] daemon cleaned up --- docs/exception_handling/index.rst | 13 +++++++++++ docs/index.rst | 1 + satella/posix/__init__.py | 7 ++---- satella/posix/daemon.py | 7 ++++-- satella/posix/pidlock.py | 36 ++++++++++++++++++++----------- satella/posix/signals.py | 10 ++++++--- 6 files changed, 52 insertions(+), 22 deletions(-) create mode 100644 docs/exception_handling/index.rst diff --git a/docs/exception_handling/index.rst b/docs/exception_handling/index.rst new file mode 100644 index 00000000..0ea44485 --- /dev/null +++ b/docs/exception_handling/index.rst @@ -0,0 +1,13 @@ +Exception handling +================== + +Satella provides a rich functionality to register exception hooks. + +Writing your own exception handlers +----------------------------------- + +To write your own exception handlers, subclass the following class: + +.. autoclass:: satella.exception_handling.BaseExceptionHandler + :members: + diff --git a/docs/index.rst b/docs/index.rst index bea56862..30e19e9e 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -14,6 +14,7 @@ Welcome to satella's documentation! coding/concurrent instrumentation/traceback instrumentation/metrics + exception_handling/index json posix recipes diff --git a/satella/posix/__init__.py b/satella/posix/__init__.py index 183ac7e0..88c5ed05 100644 --- a/satella/posix/__init__.py +++ b/satella/posix/__init__.py @@ -1,17 +1,13 @@ -# coding=UTF-8 """ -UNIX things +POSIX things """ -from __future__ import print_function, absolute_import, division -import logging import os from .daemon import daemonize from .pidlock import AcquirePIDLock from .signals import hang_until_sig -logger = logging.getLogger(__name__) __all__ = [ 'daemonize', @@ -27,6 +23,7 @@ def is_running_as_root(): Is this process running as root? Checks whether EUID is 0 + :return: bool """ return os.geteuid() == 0 diff --git a/satella/posix/daemon.py b/satella/posix/daemon.py index 73615c42..69d81a02 100644 --- a/satella/posix/daemon.py +++ b/satella/posix/daemon.py @@ -20,6 +20,9 @@ logger = logging.getLogger(__name__) DEVNULL = '/dev/null' +__all__ = ['daemonize'] + + def daemonize(exit_via: tp.Callable = sys.exit, redirect_std_to_devnull: bool = True, uid: tp.Optional[int] = None, @@ -58,10 +61,10 @@ def daemonize(exit_via: tp.Callable = sys.exit, _parse_ug(gid, grp, 'gr_gid', os.setegid) -def _parse_ug(no, module, fieldname, osfun): +def _parse_ug(no, module, field_name, osfun): if no is not None: if isinstance(no, str): - no = getattr(module.getpwnam(no), fieldname) + no = getattr(module.getpwnam(no), field_name) osfun(no) diff --git a/satella/posix/pidlock.py b/satella/posix/pidlock.py index ef920b07..30ded11a 100644 --- a/satella/posix/pidlock.py +++ b/satella/posix/pidlock.py @@ -24,13 +24,17 @@ class AcquirePIDLock: Usage: - with AcquirePIDLock('myservice.pid'): + >>> with AcquirePIDLock('myservice.pid'): + >>> ... rest of code .. - .. rest of code .. + Or alternatively - Exiting the context manager deletes the file. + >>> pid_lock = AcquirePIDLock('myservice.pid') + >>> pid_lock.acquire() + >>> ... + >>> pid_lock.release() - The constructor doesn't throw, __enter__ does, one of: + The constructor doesn't throw, __enter__ or acquire() does, one of: * AcquirePIDLock.FailedToAcquire - base class for errors. Thrown if can't read the file * AcquirePIDLock.LockIsHeld - lock is already held. This has two attributes - pid (int), the PID of holder, @@ -55,8 +59,18 @@ class AcquirePIDLock: self.fileno = None - def _acquire(self): - """The mechanical process of acquisition""" + def release(self): + if self.fileno is not None: + os.close(self.fileno) + os.unlink(self.path) + + def acquire(self): + """ + Acquire the PID lock + + :raises LockIsHeld: if lock if held + :raises FailedToAcquire: if for example a directory exists in that place + """ try: self.fileno = os.open(self.path, os.O_CREAT | os.O_EXCL) except (IOError, OSError): @@ -69,7 +83,7 @@ class AcquirePIDLock: 'PID file found but doesn''t have an int, skipping') return except IOError as e: - raise FailedToAcquire() + raise FailedToAcquire(repr(e)) # Is this process alive? try: @@ -81,17 +95,15 @@ class AcquirePIDLock: def __enter__(self): try: - self._acquire() + self.acquire() except LockIsHeld as e: if self.delete_on_dead and (not e.is_alive): os.unlink(self.path) - self._acquire() + self.acquire() else: raise self.success = True def __exit__(self, exc_type, exc_val, exc_tb): - if self.fileno is not None: - os.close(self.fileno) - os.unlink(self.path) + self.release() diff --git a/satella/posix/signals.py b/satella/posix/signals.py index 9c3b1959..ad51aa5a 100644 --- a/satella/posix/signals.py +++ b/satella/posix/signals.py @@ -14,10 +14,14 @@ def __sighandler(a, b): end = True -def hang_until_sig(extra_signals: tp.Optional[tp.List] = None): - """Will hang until this process receives SIGTERM or SIGINT. +def hang_until_sig(extra_signals: tp.Optional[tp.List[int]] = None): + """ + Will hang until this process receives SIGTERM or SIGINT. If you pass extra signal IDs (signal.SIG*) with extra_signals, - then also on those signals this call will release.""" + then also on those signals this call will release. + + :param extra_signals: a list of extra signals to listen to + """ extra_signals = extra_signals or [] global end -- GitLab