# plugins/docker/scheduler.py from __future__ import annotations import json import logging from datetime import datetime, timezone from fabledscryer.core.scheduler import ScheduledTask from fabledscryer.core.alerts import record_metric logger = logging.getLogger(__name__) def make_task(app) -> ScheduledTask: interval = int( app.config["PLUGINS"]["docker"].get("scrape_interval_seconds", 60) ) async def scrape(): await _do_scrape(app) return ScheduledTask( name="docker_scrape", coro_factory=scrape, interval_seconds=interval, run_on_startup=True, ) async def _do_scrape(app) -> None: from .scraper import scrape_docker from .models import DockerContainer, DockerMetric cfg = app.config["PLUGINS"]["docker"] socket_path = cfg.get("socket_path", "/var/run/docker.sock") include_stopped = bool(cfg.get("include_stopped", False)) try: containers = await scrape_docker(socket_path, include_stopped) except ConnectionError as exc: logger.error("Docker scrape failed: %s", exc) return except Exception: logger.exception("Docker scrape error") return now = datetime.now(timezone.utc) async with app.db_sessionmaker() as session: async with session.begin(): for c in containers: # Upsert container state existing = await session.get(DockerContainer, c["name"]) if existing is None: existing = DockerContainer(name=c["name"]) session.add(existing) existing.container_id = c["container_id"] existing.image = c["image"] existing.status = c["status"] existing.cpu_pct = c["cpu_pct"] existing.mem_usage_bytes = c["mem_usage_bytes"] existing.mem_limit_bytes = c["mem_limit_bytes"] existing.mem_pct = c["mem_pct"] existing.restart_count = c["restart_count"] existing.ports_json = json.dumps(c["ports"]) existing.started_at = c["started_at"] existing.scraped_at = now # Time-series metric (running containers only) if c["status"] == "running" and c["cpu_pct"] is not None: session.add(DockerMetric( container_name=c["name"], scraped_at=now, cpu_pct=c["cpu_pct"], mem_pct=c["mem_pct"] or 0.0, mem_usage_bytes=c["mem_usage_bytes"] or 0, )) # Feed alert pipeline await record_metric( session=session, source_module="docker", resource_name=c["name"], metric_name="cpu_pct", value=c["cpu_pct"], ) if c["mem_pct"] is not None: await record_metric( session=session, source_module="docker", resource_name=c["name"], metric_name="mem_pct", value=c["mem_pct"], )