moving config storage to mongo

This commit is contained in:
TPV committed 2026-07-13 10:25:07 -07:00
1 parent 9bc34d4dc9
commit 7d070dec40
2 files changed
+43 -30

No files matched your search

+29 -19
View File
@@ -1,11 +1,16 @@
"""Config loading and mode helpers shared across monitors and the bot.""" """Config loading and mode helpers shared across monitors and the bot."""
import json
import logging import logging
import pathlib
from enum import Enum from enum import Enum
from monitor_utils.constants import LOGGERS from monitor_utils.constants import LOGGERS
from monitor_utils.database import get_collection
CONFIGS_COLLECTION_NAME = "configs"
class ConfigNotFoundError(Exception):
"""Raised when a monitor has no config document in Mongo."""
class DevelopmentMode(str, Enum): class DevelopmentMode(str, Enum):
@@ -21,29 +26,34 @@ def is_production(development_mode: DevelopmentMode) -> bool:
return development_mode == DevelopmentMode.PRODUCTION return development_mode == DevelopmentMode.PRODUCTION
def get_config( async def get_config(monitor_name: str, use_production: bool = False) -> dict:
monitor_name: str, """Load a monitor's config document from Mongo.
config_dir: str | pathlib.Path = "configs",
test_config_dir: str | pathlib.Path = "tests/configs", Reads the configs collection in production and configs_testing in
use_production_path: bool = False, development, so a dev run never reads production routing.
) -> tuple[dict, pathlib.Path]:
"""Load a monitor's JSON config from the production or test directory.
Args: Args:
monitor_name: Monitor name with or without a .json suffix. monitor_name: Monitor identifier (the config document _id).
config_dir: Directory holding production configs. use_production: Read the production configs collection instead of
test_config_dir: Directory holding test configs. configs_testing.
use_production_path: Load from config_dir instead of test_config_dir.
Returns: Returns:
Tuple of the parsed config dict and the resolved config path. The config document, including its categories and channels.
Raises:
ConfigNotFoundError: When no document exists for the monitor.
""" """
monitor_name = monitor_name.replace(".json", "") collection_name = (
base = config_dir if use_production_path else test_config_dir CONFIGS_COLLECTION_NAME
config_path = pathlib.Path(base) / f"{monitor_name}.json" if use_production
with open(config_path) as f: else f"{CONFIGS_COLLECTION_NAME}_testing"
return json.load(f), config_path )
config = await get_collection(collection_name).find_one({"_id": monitor_name})
if config is None:
raise ConfigNotFoundError(monitor_name)
return config
def set_logger_levels(loggers: list[str] = LOGGERS, level: int = logging.WARNING): def set_logger_levels(loggers: list[str] = LOGGERS, level: int = logging.WARNING):
+14 -11
View File
@@ -28,18 +28,20 @@ from monitor_utils.sessions import get_base_session, get_tls_session
LOGGER = logging.getLogger(__name__) LOGGER = logging.getLogger(__name__)
def init_monitor( async def init_monitor(
monitor_name: str, monitor_name: str,
development_mode: DevelopmentMode, development_mode: DevelopmentMode,
production_proxy_path: str = "proxies.txt", production_proxy_path: str = "proxies.txt",
testing_proxy_path: str = "configs/proxies.txt", testing_proxy_path: str = "configs/proxies.txt",
logging_level=LOGGING_LEVEL, logging_level=LOGGING_LEVEL,
) -> tuple[list[str], AsyncIOMotorCollection, AioProxies]: ) -> tuple[list[str] | dict[str, str], AsyncIOMotorCollection, AioProxies]:
"""Run shared monitor startup and return categories, collection, and proxies. """Run shared monitor startup and return categories, collection, and proxies.
Configures JSON logging under the monitor's name, applies logger levels, Configures JSON logging under the monitor's name, applies logger levels,
loads the monitor config and Mongo collection, and loads proxies from the loads the monitor config and Mongo collection, and loads proxies from the
production or testing path based on development_mode. production or testing path based on development_mode. Async because the
config now lives in Mongo; call it from inside the monitor's event loop
(in main), not at module import.
Args: Args:
monitor_name: Monitor identifier used for logging and config lookup. monitor_name: Monitor identifier used for logging and config lookup.
@@ -61,7 +63,7 @@ def init_monitor(
output="json", output="json",
) )
set_logger_levels() set_logger_levels()
category_names, _, collection = setup_config( category_names, _, collection = await setup_config(
monitor_name=monitor_name, development_mode=development_mode monitor_name=monitor_name, development_mode=development_mode
) )
proxy_path = production_proxy_path if use_production else testing_proxy_path proxy_path = production_proxy_path if use_production else testing_proxy_path
@@ -69,17 +71,18 @@ def init_monitor(
return category_names, collection, proxies return category_names, collection, proxies
def setup_config( async def setup_config(
monitor_name: str, development_mode: DevelopmentMode monitor_name: str, development_mode: DevelopmentMode
) -> tuple[list[str], dict[int], AsyncIOMotorCollection]: ) -> tuple[list[str] | dict[str, str], dict[str, str | list[str]], AsyncIOMotorCollection]:
"""Load monitor config and resolve the Mongo collection for the mode. """Load monitor config and resolve the Mongo collection for the mode.
Testing mode appends a _testing suffix to the collection name so Testing mode reads the configs_testing collection and appends a _testing
production data is never touched during development. suffix to the product collection name so production data is never touched
during development.
Args: Args:
monitor_name: Monitor identifier used for config and collection lookup. monitor_name: Monitor identifier used for config and collection lookup.
development_mode: Selects the production or testing config path and development_mode: Selects the production or testing config and
collection. collection.
Returns: Returns:
@@ -87,9 +90,9 @@ def setup_config(
""" """
use_production = is_production(development_mode) use_production = is_production(development_mode)
config, _ = get_config( config = await get_config(
monitor_name=monitor_name, monitor_name=monitor_name,
use_production_path=use_production, use_production=use_production,
) )
category_names = config["categories"] category_names = config["categories"]