mirror of
https://github.com/outbackdingo/patroni.git
synced 2026-08-25 14:53:37 +00:00
Add docstrings and type annotations to patroni/daemon.py (#2610)
References: PAT-38
This commit is contained in:
+90
-15
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user