revert(watchdog): usuniecie integracji ze Slackiem
Na zyczenie uzytkownika. Alerty zostaja wylacznie w Sentry - z eskalacja poziomu i kubelkami wieku w fingerprincie z poprzedniego commita, wiec sama poprawa powiadamiania zostaje nienaruszona. Usuniete: app/notify/ (caly pakiet), job watchdog-digest, parametr to_slack w run_ingest_freshness_watchdog oraz klucze konfiguracji sched_watchdog_digest_hours, slack_bot_token i slack_channel. Zadna wartosc SLACK nigdy nie trafila do .env ani do compose, wiec nic nie bylo wysylane. Po usunieciu watchdog dalej sprawdza 41 zrodel (sceny + filmy), scheduler rejestruje juz tylko ingest-watchdog. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
6e056b81c2
commit
6199577ae7
6 changed files with 2 additions and 110 deletions
|
|
@ -129,14 +129,6 @@ class Settings(BaseSettings):
|
||||||
ingest_watchdog_movie_max_age_hours: int = Field(
|
ingest_watchdog_movie_max_age_hours: int = Field(
|
||||||
default=72, validation_alias="GOON_INGEST_WATCHDOG_MOVIE_MAX_AGE_HOURS"
|
default=72, validation_alias="GOON_INGEST_WATCHDOG_MOVIE_MAX_AGE_HOURS"
|
||||||
)
|
)
|
||||||
# Dobowy digest zamrożonych źródeł na Slacka. Sentry dostaje alert co 6h, ale
|
|
||||||
# tam sygnał ginął (patrz docstring ingest_watchdog). 0 = off.
|
|
||||||
sched_watchdog_digest_hours: int = Field(
|
|
||||||
default=24, validation_alias="GOON_SCHED_WATCHDOG_DIGEST_HOURS"
|
|
||||||
)
|
|
||||||
# Slack — bez OBU wartości powiadomienia są no-opem. Kanału nie zgadujemy.
|
|
||||||
slack_bot_token: str = Field(default="", validation_alias="GOON_SLACK_BOT_TOKEN")
|
|
||||||
slack_channel: str = Field(default="", validation_alias="GOON_SLACK_CHANNEL")
|
|
||||||
# Śmieciowi performerzy — kategorie i studia podszywające się pod osoby („Creampie",
|
# Śmieciowi performerzy — kategorie i studia podszywające się pod osoby („Creampie",
|
||||||
# „Natural tits", „Brazzers"). Audyt 2026-07-27: 277 rekordów, 33 784 przypisania.
|
# „Natural tits", „Brazzers"). Audyt 2026-07-27: 277 rekordów, 33 784 przypisania.
|
||||||
# Odrastają, bo tube-search dokleja performera po jednym tokenie. 24h. 0 = off.
|
# Odrastają, bo tube-search dokleja performera po jednym tokenie. 24h. 0 = off.
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
"""Powiadomienia wychodzace (Slack)."""
|
|
||||||
|
|
@ -1,50 +0,0 @@
|
||||||
"""Wysyłka powiadomień na Slacka — kanał, który człowiek realnie czyta.
|
|
||||||
|
|
||||||
Powód powstania (2026-08-03): watchdog świeżości poprawnie wykrywał zamrożone źródła
|
|
||||||
(vjav stał 12 dni, streamporn.vip 23), ale sygnał ginął. Szedł wyłącznie do Sentry ze
|
|
||||||
stabilnym fingerprintem i poziomem `warning`, więc powstawało JEDNO issue przy
|
|
||||||
pierwszym wystąpieniu i potem tylko rósł mu licznik — Sentry powiadamia o nowych
|
|
||||||
i regresjach, nie o kolejnych wystąpieniach otwartego issue.
|
|
||||||
|
|
||||||
Domyślnie WYŁĄCZONE: bez `GOON_SLACK_BOT_TOKEN` i `GOON_SLACK_CHANNEL` funkcja jest
|
|
||||||
no-opem i nic nie próbuje wysyłać. Nie zgadujemy kanału.
|
|
||||||
"""
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import logging
|
|
||||||
|
|
||||||
import httpx
|
|
||||||
|
|
||||||
from app.config import get_settings
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
_API = "https://slack.com/api/chat.postMessage"
|
|
||||||
|
|
||||||
|
|
||||||
def send_slack(text: str, *, timeout: float = 15.0) -> bool:
|
|
||||||
"""Wyślij wiadomość na skonfigurowany kanał. Zwraca True gdy poszła.
|
|
||||||
|
|
||||||
Cicho zwraca False gdy brak konfiguracji — to normalny stan, nie błąd.
|
|
||||||
"""
|
|
||||||
settings = get_settings()
|
|
||||||
token = getattr(settings, "slack_bot_token", "") or ""
|
|
||||||
channel = getattr(settings, "slack_channel", "") or ""
|
|
||||||
if not token or not channel:
|
|
||||||
return False
|
|
||||||
try:
|
|
||||||
r = httpx.post(
|
|
||||||
_API,
|
|
||||||
headers={"Authorization": f"Bearer {token}"},
|
|
||||||
json={"channel": channel, "text": text},
|
|
||||||
timeout=timeout,
|
|
||||||
)
|
|
||||||
data = r.json()
|
|
||||||
if not data.get("ok"):
|
|
||||||
# Slack zwraca 200 nawet przy błędzie logicznym — sprawdzamy `ok`.
|
|
||||||
log.warning("slack: wysyłka odrzucona: %s", data.get("error"))
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
except Exception as e:
|
|
||||||
log.warning("slack: wysyłka nieudana: %s", e)
|
|
||||||
return False
|
|
||||||
|
|
@ -66,15 +66,14 @@ def run_ingest_freshness_watchdog(
|
||||||
movie_max_age_hours: int = 72,
|
movie_max_age_hours: int = 72,
|
||||||
min_history: int = 100,
|
min_history: int = 100,
|
||||||
to_sentry: bool = True,
|
to_sentry: bool = True,
|
||||||
to_slack: bool = False,
|
|
||||||
) -> dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
"""Sprawdź każde aktywne źródło: czy dostało nową treść < próg dla swojej klasy.
|
"""Sprawdź każde aktywne źródło: czy dostało nową treść < próg dla swojej klasy.
|
||||||
|
|
||||||
`min_history` odsiewa świeżo dodane źródła bez ustalonej kadencji (za mało pozycji,
|
`min_history` odsiewa świeżo dodane źródła bez ustalonej kadencji (za mało pozycji,
|
||||||
by wiedzieć, czy cisza to anomalia).
|
by wiedzieć, czy cisza to anomalia).
|
||||||
|
|
||||||
`to_sentry` / `to_slack` sterują kanałami — job co 6h woła Sentry, a osobny job
|
`to_sentry=False` daje sam odczyt (przydatne do ręcznego sprawdzenia bez
|
||||||
dobowy woła Slacka, żeby nie wysyłać tej samej listy cztery razy dziennie.
|
zaśmiecania issue).
|
||||||
"""
|
"""
|
||||||
from app.connectors import get_movie_connectors # noqa: PLC0415
|
from app.connectors import get_movie_connectors # noqa: PLC0415
|
||||||
from app.connectors.direct_scrapers import ( # noqa: PLC0415
|
from app.connectors.direct_scrapers import ( # noqa: PLC0415
|
||||||
|
|
@ -169,16 +168,4 @@ def run_ingest_freshness_watchdog(
|
||||||
except Exception: # pragma: no cover - Sentry off / brak DSN
|
except Exception: # pragma: no cover - Sentry off / brak DSN
|
||||||
log.exception("ingest-watchdog: Sentry capture failed")
|
log.exception("ingest-watchdog: Sentry capture failed")
|
||||||
|
|
||||||
if to_slack:
|
|
||||||
from app.notify.slack import send_slack # noqa: PLC0415
|
|
||||||
|
|
||||||
lines = [f"*Zamrożone źródła ingestu* ({len(stale)}/{len(checks)})"]
|
|
||||||
for x in stale:
|
|
||||||
days = x["age_hours"] / 24.0
|
|
||||||
lines.append(
|
|
||||||
f"• `{x['origin']}` ({x['kind']}) — {days:.1f} dnia bez nowych treści "
|
|
||||||
f"(próg {x['max_age_hours']}h, {x['total']} pozycji w bazie)"
|
|
||||||
)
|
|
||||||
send_slack("\n".join(lines))
|
|
||||||
|
|
||||||
return {"checked": len(checks), "stale": stale}
|
return {"checked": len(checks), "stale": stale}
|
||||||
|
|
|
||||||
|
|
@ -338,7 +338,6 @@ def _job_ingest_watchdog(
|
||||||
max_age_hours=max_age_hours,
|
max_age_hours=max_age_hours,
|
||||||
search_max_age_hours=search_max_age_hours,
|
search_max_age_hours=search_max_age_hours,
|
||||||
movie_max_age_hours=movie_max_age_hours,
|
movie_max_age_hours=movie_max_age_hours,
|
||||||
to_sentry=True,
|
|
||||||
)
|
)
|
||||||
if res["stale"]:
|
if res["stale"]:
|
||||||
log.warning("[scheduler] ingest-watchdog: %d stale origin(s)", len(res["stale"]))
|
log.warning("[scheduler] ingest-watchdog: %d stale origin(s)", len(res["stale"]))
|
||||||
|
|
@ -346,26 +345,6 @@ def _job_ingest_watchdog(
|
||||||
log.exception("[scheduler] ingest-watchdog failed")
|
log.exception("[scheduler] ingest-watchdog failed")
|
||||||
|
|
||||||
|
|
||||||
def _job_watchdog_digest(
|
|
||||||
max_age_hours: int, search_max_age_hours: int, movie_max_age_hours: int
|
|
||||||
) -> None:
|
|
||||||
"""Dobowy digest zamrożonych źródeł na Slacka. Osobno od joba co 6h, żeby nie
|
|
||||||
wysyłać tej samej listy cztery razy dziennie; Sentry zostaje kanałem maszynowym,
|
|
||||||
Slack ludzkim. Bez GOON_SLACK_BOT_TOKEN i GOON_SLACK_CHANNEL to no-op."""
|
|
||||||
try:
|
|
||||||
from app.scheduler.ingest_watchdog import run_ingest_freshness_watchdog
|
|
||||||
|
|
||||||
run_ingest_freshness_watchdog(
|
|
||||||
max_age_hours=max_age_hours,
|
|
||||||
search_max_age_hours=search_max_age_hours,
|
|
||||||
movie_max_age_hours=movie_max_age_hours,
|
|
||||||
to_sentry=False,
|
|
||||||
to_slack=True,
|
|
||||||
)
|
|
||||||
except Exception:
|
|
||||||
log.exception("[scheduler] watchdog-digest failed")
|
|
||||||
|
|
||||||
|
|
||||||
def _job_hetzner_monitor() -> None:
|
def _job_hetzner_monitor() -> None:
|
||||||
"""Hetzner Cloud bandwidth monitor — alert do Sentry przy progach % included_traffic.
|
"""Hetzner Cloud bandwidth monitor — alert do Sentry przy progach % included_traffic.
|
||||||
No-op gdy brak HETZNER_API_TOKEN/SERVER_ID w env (loguje że wyłączony)."""
|
No-op gdy brak HETZNER_API_TOKEN/SERVER_ID w env (loguje że wyłączony)."""
|
||||||
|
|
@ -576,19 +555,6 @@ def build_scheduler(cfg: dict[str, Any]) -> BlockingScheduler:
|
||||||
cfg["ingest_watchdog_hours"], wd_max_age, wd_search_max_age, wd_movie_max_age,
|
cfg["ingest_watchdog_hours"], wd_max_age, wd_search_max_age, wd_movie_max_age,
|
||||||
)
|
)
|
||||||
|
|
||||||
if cfg.get("watchdog_digest_hours"):
|
|
||||||
sched.add_job(
|
|
||||||
lambda: _job_watchdog_digest(wd_max_age, wd_search_max_age, wd_movie_max_age),
|
|
||||||
IntervalTrigger(
|
|
||||||
hours=cfg["watchdog_digest_hours"], start_date=INTERVAL_ANCHOR
|
|
||||||
),
|
|
||||||
id="watchdog_digest",
|
|
||||||
replace_existing=True,
|
|
||||||
max_instances=1,
|
|
||||||
coalesce=True,
|
|
||||||
)
|
|
||||||
log.info("scheduler: watchdog-digest (Slack) every %dh", cfg["watchdog_digest_hours"])
|
|
||||||
|
|
||||||
if cfg.get("hetzner_monitor_hours"):
|
if cfg.get("hetzner_monitor_hours"):
|
||||||
sched.add_job(
|
sched.add_job(
|
||||||
_job_hetzner_monitor,
|
_job_hetzner_monitor,
|
||||||
|
|
|
||||||
|
|
@ -237,8 +237,6 @@ def run_forever() -> int:
|
||||||
"ingest_watchdog_movie_max_age_hours": getattr(
|
"ingest_watchdog_movie_max_age_hours": getattr(
|
||||||
settings, "ingest_watchdog_movie_max_age_hours", 72
|
settings, "ingest_watchdog_movie_max_age_hours", 72
|
||||||
),
|
),
|
||||||
# Dobowy digest na Slacka (Sentry gubił sygnał na stabilnym fingerprincie).
|
|
||||||
"watchdog_digest_hours": getattr(settings, "sched_watchdog_digest_hours", 24) or None,
|
|
||||||
# Hetzner Cloud bandwidth monitor — alert do Sentry przy progach % included.
|
# Hetzner Cloud bandwidth monitor — alert do Sentry przy progach % included.
|
||||||
# No-op gdy brak HETZNER_API_TOKEN/SERVER_ID (sam job może być on).
|
# No-op gdy brak HETZNER_API_TOKEN/SERVER_ID (sam job może być on).
|
||||||
"hetzner_monitor_hours": getattr(settings, "sched_hetzner_monitor_hours", 6) or None,
|
"hetzner_monitor_hours": getattr(settings, "sched_hetzner_monitor_hours", 6) or None,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue