diff --git a/.gitignore b/.gitignore index 90dbfef..9563722 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,5 @@ karton.ini config.ini docs/_build .mypy_cache +build +karton_core.egg-info/ diff --git a/docs/advanced_concepts.rst b/docs/advanced_concepts.rst index 224329c..3d75953 100644 --- a/docs/advanced_concepts.rst +++ b/docs/advanced_concepts.rst @@ -230,3 +230,19 @@ The simplest way to do that is to perform all of these actions synchronously, in # If analysis has been finished: get the results and process them analysis = sandbox.get_results(analysis_id) self.process_results(analysis) + + +Karton debug mode +----------------- + +During your karton services development endeavours you'll often have the urge to test them out on the production environment. + +While this is totally fine, you have to be careful not to disrupt the production services by consuming the tasks meant for them. In most cases you also don't want to propagate logs from your experiments to the production log pipeline. + +Karton debug mode was crafted especially for this purpose. It adds a random suffix to the service identity to create a new, non-conflicting task queue. +It also permanently sets the consumer persistence to False and disables log forwarding. + +You can enable it by setting: +- :code:`KARTON_KARTON_DEBUG` environment value to "1" +- :code:`debug` parameter to `1` in the :code:`[karton]` config section +- :code:`--debug` command-line parameter diff --git a/docs/service_configuration.rst b/docs/service_configuration.rst index 79b0117..50ab969 100644 --- a/docs/service_configuration.rst +++ b/docs/service_configuration.rst @@ -48,6 +48,7 @@ Common Karton configuration fields are listed below: [redis] socket_timeout Socket timeout for Redis operations in seconds (default: 30, use 0 to turn off if timeout doesn't work properly) [karton] identity Karton service identity override (overrides the name provided in class / constructor arguments) [karton] persistent Karton service queue persistency override + [karton] debug Karton debug mode for service development [karton] task_timeout Karton service task execution timeout in seconds. Useful if your service sometimes hangs. Karton will schedule SIGALRM if this value is set. [logging] level Logging level for Karton service logger (default: INFO) [signaling] status Turns on producing of 'karton.signaling.status' tasks, signalling the task start and finish events by Karton service (default: 0, off) @@ -90,6 +91,7 @@ All settings can be set using command-line. --identity IDENTITY Alternative identity for Karton service --log-level LOG_LEVEL Logging level of Karton logger + --debug Enable debugging mode --setup-bucket Create missing bucket in S3 storage --disable-gc Do not run GC in this instance --disable-router Do not run task routing in this instance diff --git a/karton/core/base.py b/karton/core/base.py index 3d8420c..846509e 100644 --- a/karton/core/base.py +++ b/karton/core/base.py @@ -1,6 +1,7 @@ import abc import argparse import logging +import os import textwrap from contextlib import contextmanager from typing import Optional, Union, cast @@ -44,6 +45,11 @@ def __init__( if self.config.has_option("karton", "identity"): self.identity = self.config.get("karton", "identity") + self.debug = self.config.getboolean("karton", "debug", False) + + if self.debug: + self.identity += "-" + os.urandom(4).hex() + "-dev" + self.service_info = None if self.identity is not None and self.with_service_info: self.service_info = KartonServiceInfo( @@ -101,7 +107,9 @@ def setup_logger(self, level: Optional[Union[str, int]] = None) -> None: logging.Formatter("[%(asctime)s][%(levelname)s] %(message)s") ) logger.addHandler(stream_handler) - logger.addHandler(self._log_handler) + + if not self.debug: + logger.addHandler(self._log_handler) @property def log_handler(self) -> KartonLogHandler: @@ -154,6 +162,9 @@ def args_parser(cls) -> argparse.ArgumentParser: "--identity", help="Alternative identity for Karton service" ) parser.add_argument("--log-level", help="Logging level of Karton logger") + parser.add_argument( + "--debug", help="Enable debugging mode", action="store_true", default=None + ) return parser @classmethod @@ -166,7 +177,10 @@ def config_from_args(cls, config: Config, args: argparse.Namespace) -> None: """ config.load_from_dict( { - "karton": {"identity": args.identity}, + "karton": { + "identity": args.identity, + "debug": args.debug, + }, "logging": {"level": args.log_level}, } ) diff --git a/karton/core/karton.py b/karton/core/karton.py index 0f46c36..88fc058 100644 --- a/karton/core/karton.py +++ b/karton/core/karton.py @@ -121,8 +121,9 @@ def __init__( if self.filters is None: raise ValueError("Cannot bind consumer on Empty binds") - self.persistent = self.config.getboolean( - "karton", "persistent", self.persistent + self.persistent = ( + self.config.getboolean("karton", "persistent", self.persistent) + and not self.debug ) self.task_timeout = self.config.getint("karton", "task_timeout") self.current_task: Optional[Task] = None