Phase 2 Health-Check tenant-fähig + Historie
- migrations/2026-05-09d_source_health_history.py NEU: source_health_history-Tabelle
(Append-only Verlauf der Health-Check-Runs mit run_id und archived_at)
- shared/services/source_health.py:
- tenant_id IS NULL Filter raus -> auch Tenant-Quellen werden gecheckt
- Mojibake (Triple-Encoded UTF-8) via ftfy gefixt
- DELETE FROM source_health_checks: vorher Stand mit run_id (uuid4) in
source_health_history archivieren -> kein Datenverlust mehr
- User-Agent + Timeout aus config.HEALTH_CHECK_* statt hardcoded
- routers/sources.py /health/run-stream: gleiche Änderungen wie oben
- config.py: HEALTH_CHECK_USER_AGENT + HEALTH_CHECK_TIMEOUT_S ergänzt
Dieser Commit ist enthalten in:
@@ -1,5 +1,6 @@
|
||||
"""Grundquellen-Verwaltung und Kundenquellen-Übersicht."""
|
||||
import logging
|
||||
import uuid
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, status, Request
|
||||
from fastapi.responses import StreamingResponse
|
||||
@@ -10,6 +11,7 @@ import aiosqlite
|
||||
from auth import get_current_admin
|
||||
from database import db_dependency
|
||||
from audit import log_action, get_client_ip, row_to_dict
|
||||
from config import HEALTH_CHECK_USER_AGENT, HEALTH_CHECK_TIMEOUT_S
|
||||
from shared.source_rules import (
|
||||
discover_source,
|
||||
discover_all_feeds,
|
||||
@@ -564,7 +566,7 @@ async def run_health_check_stream(
|
||||
# Quellen laden
|
||||
cursor = await db.execute(
|
||||
"SELECT id, name, url, domain, source_type, article_count, last_seen_at "
|
||||
"FROM sources WHERE status = 'active' AND tenant_id IS NULL"
|
||||
"FROM sources WHERE status = 'active'" # tenant + global
|
||||
)
|
||||
sources = [dict(row) for row in await cursor.fetchall()]
|
||||
sources_with_url = [s for s in sources if s["url"]]
|
||||
@@ -577,6 +579,15 @@ async def run_health_check_stream(
|
||||
# Phase 1: Erreichbarkeit
|
||||
yield f"data: {_json.dumps({'phase': 'check', 'checked': 0, 'total': total, 'current': ''})}\n\n"
|
||||
|
||||
# Bisherigen Stand archivieren, dann frisch
|
||||
run_id = uuid.uuid4().hex[:12]
|
||||
await db.execute(
|
||||
"INSERT INTO source_health_history "
|
||||
"(run_id, source_id, check_type, status, message, details, checked_at) "
|
||||
"SELECT ?, source_id, check_type, status, message, details, checked_at "
|
||||
"FROM source_health_checks",
|
||||
(run_id,),
|
||||
)
|
||||
await db.execute("DELETE FROM source_health_checks")
|
||||
await db.commit()
|
||||
|
||||
@@ -584,8 +595,8 @@ async def run_health_check_stream(
|
||||
checked = 0
|
||||
|
||||
async with httpx.AsyncClient(
|
||||
timeout=15.0, follow_redirects=True,
|
||||
headers={"User-Agent": "Mozilla/5.0 (compatible; OSINT-Monitor/1.0)"},
|
||||
timeout=HEALTH_CHECK_TIMEOUT_S, follow_redirects=True,
|
||||
headers={"User-Agent": HEALTH_CHECK_USER_AGENT},
|
||||
) as client:
|
||||
for source in sources_with_url:
|
||||
try:
|
||||
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren