Add docstrings and type annotations to patroni/daemon.py (#2610)

References: PAT-38
This commit is contained in:
Israel
2023-03-23 13:41:16 +01:00
committed by GitHub
parent 60723f5fa4
commit 84353b88c9
+90 -15
View File
@@ -1,3 +1,8 @@
"""Daemon processes abstraction module.
This module implements abstraction classes and functions for creating and managing daemon processes in Patroni.
Currently it is only used for the main "Thread" of ``patroni`` and ``patroni_raft_controller`` commands.
"""
from __future__ import print_function
import abc
@@ -6,11 +11,30 @@ import signal
import sys
from threading import Lock
from typing import Any, Optional, Type
from .config import Config
from .validator import Schema
class AbstractPatroniDaemon(abc.ABC):
"""A Patroni daemon process.
def __init__(self, config):
.. note::
When inheriting from :class:`AbstractPatroniDaemon` you are expected to define the methods :func:`_run_cycle`
to determine what it should do in each execution cycle, and :func:`_shutdown` to determine what it should do
when shutting down.
:ivar logger: log handler used by this daemon.
:ivar config: configuration options for this daemon.
"""
def __init__(self, config: Config) -> None:
"""Set up signal handlers, logging handler and configuration.
:param config: configuration options for this daemon.
"""
from patroni.log import PatroniLogger
self.setup_signal_handlers()
@@ -19,20 +43,44 @@ class AbstractPatroniDaemon(abc.ABC):
self.config = config
AbstractPatroniDaemon.reload_config(self, local=True)
def sighup_handler(self, *args):
def sighup_handler(self, *_: Any) -> None:
"""Handle SIGHUP signals.
Flag the daemon as "SIGHUP received".
"""
self._received_sighup = True
def api_sigterm(self):
def api_sigterm(self) -> bool:
"""Guarantee only a single SIGTERM is being processed.
Flag the daemon as "SIGTERM received" with a lock-based approach.
:returns: ``True`` if the daemon was flagged as "SIGTERM received".
"""
ret = False
with self._sigterm_lock:
if not self._received_sigterm:
self._received_sigterm = True
return True
ret = True
return ret
def sigterm_handler(self, *args):
def sigterm_handler(self, *_: Any) -> None:
"""Handle SIGTERM signals.
Terminate the daemon process through :func:`api_sigterm`.
"""
if self.api_sigterm():
sys.exit()
def setup_signal_handlers(self):
def setup_signal_handlers(self) -> None:
"""Set up daemon signal handlers.
Set up SIGHUP and SIGTERM signal handlers.
.. note::
SIGHUP is only handled in non-Windows environments.
"""
self._received_sighup = False
self._sigterm_lock = Lock()
self._received_sigterm = False
@@ -41,19 +89,34 @@ class AbstractPatroniDaemon(abc.ABC):
signal.signal(signal.SIGTERM, self.sigterm_handler)
@property
def received_sigterm(self):
def received_sigterm(self) -> bool:
"""If daemon was signaled with SIGTERM."""
with self._sigterm_lock:
return self._received_sigterm
def reload_config(self, sighup=False, local=False):
def reload_config(self, sighup: Optional[bool] = False, local: Optional[bool] = False) -> None:
"""Reload configuration.
:param sighup: if it is related to a SIGHUP signal.
The sighup parameter could be used in the method overridden in a child class.
:param local: will be ``True`` if there are changes in the local configuration file.
"""
if local:
self.logger.reload_config(self.config.get('log', {}))
@abc.abstractmethod
def _run_cycle(self):
"""_run_cycle"""
def _run_cycle(self) -> None:
"""Define what the daemon should do in each execution cycle.
def run(self):
Keep being called in the daemon's main loop until the daemon is eventually terminated.
"""
def run(self) -> None:
"""Run the daemon process.
Start the logger thread and keep running execution cycles until a SIGTERM is eventually received. Also reload
configuration uppon receiving SIGHUP.
"""
self.logger.start()
while not self.received_sigterm:
if self._received_sighup:
@@ -63,17 +126,29 @@ class AbstractPatroniDaemon(abc.ABC):
self._run_cycle()
@abc.abstractmethod
def _shutdown(self):
"""_shutdown"""
def _shutdown(self) -> None:
"""Define what the daemon should do when shutting down."""
def shutdown(self):
def shutdown(self) -> None:
"""Shut the daemon down when a SIGTERM is received.
Shut down the daemon process and the logger thread.
"""
with self._sigterm_lock:
self._received_sigterm = True
self._shutdown()
self.logger.shutdown()
def abstract_main(cls, validator=None):
def abstract_main(cls: Type[AbstractPatroniDaemon], validator: Optional[Schema] = None) -> None:
"""Create the main entry point of a given daemon process.
Expose a basic argument parser, parse the command-line arguments, and run the given daemon process.
:param cls: a class that should inherit from :class:`AbstractPatroniDaemon`.
:param validator: used to validate the daemon configuration schema, if requested by the user through
``--validate-config`` CLI option.
"""
import argparse
from .config import Config, ConfigParseError