Files
2026-08-31 14:33:53 +09:00

30 lines
1.0 KiB
Python

"""Helpers shared by collectors: failure isolation and timing."""
from __future__ import annotations
import logging
import time
from collections.abc import Callable
from us2kr.logging_setup import mask_secrets
log = logging.getLogger(__name__)
def run_safely[T](name: str, fn: Callable[[], T], default: T, gaps: list[str]) -> T:
"""Run a collector; on any exception log it, append a gap note and return `default`.
The pipeline must never die because one data source is down.
"""
t0 = time.monotonic()
try:
result = fn()
log.info("collector %s ok in %.1fs", name, time.monotonic() - t0)
return result
except Exception as exc: # deliberate: isolate every failure
log.exception("collector %s failed", name)
# Gap notes end up in the briefing / Telegram / LLM prompt: never let a URL with a key through.
detail = mask_secrets(str(exc)).split(" for url: ", 1)[0][:120]
gaps.append(f"{name}: {type(exc).__name__}: {detail}")
return default