fix: Mi2-Mi4 + Mi1 partial — version pins, file-lock, catalog lock, __main__ tests
- Mi2: requirements.txt — Obergrenzen hinzugefügt (<3.0, <5.0, etc.) - Mi3: cmd_scan() — File-Lock via fcntl (data_dir/.scan.lock) - Mi4: refresh_catalog() — Cache-Check unter self._lock (thread-safe) - Mi1: tests/test_main.py — 17 neue Tests (__main__ Coverage 10% → 18%) - 294/294 Tests grün
This commit is contained in:
parent
eeb3ac6c28
commit
de5be23d23
5 changed files with 287 additions and 12 deletions
|
|
@ -15,6 +15,7 @@ Subcommands:
|
|||
status Show baseline age, last scan, open changes
|
||||
"""
|
||||
import argparse
|
||||
import fcntl
|
||||
import json
|
||||
import logging
|
||||
import re
|
||||
|
|
@ -742,8 +743,26 @@ def cmd_check(args: argparse.Namespace, cfg: dict) -> int:
|
|||
|
||||
|
||||
def cmd_scan(args: argparse.Namespace, cfg: dict) -> int:
|
||||
"""crawl + check. Führt fällige Wochen-Prüfungen automatisch mit aus."""
|
||||
"""crawl + check. Führt fällige Wochen-Prüfungen automatisch mit aus.
|
||||
|
||||
Nutzt einen File-Lock (data_dir/.scan.lock), um parallele Scans derselben
|
||||
Site zu verhindern (Cron-Job + manueller Aufruf). Timeout: 120 s."""
|
||||
logger = logging.getLogger("scanner.scan")
|
||||
|
||||
# --- File-Lock gegen parallele Scans ---
|
||||
data_dir = cfg.get("data_dir")
|
||||
lock_path = Path(data_dir) / ".scan.lock" if data_dir else None
|
||||
lock_fd = None
|
||||
if lock_path:
|
||||
try:
|
||||
lock_fd = open(lock_path, "w")
|
||||
fcntl.flock(lock_fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
||||
lock_fd.write(f"{datetime.now(timezone.utc).isoformat()}\n")
|
||||
lock_fd.flush()
|
||||
except BlockingIOError:
|
||||
print(f" Scan läuft bereits (Lock: {lock_path}). Bitte warten.")
|
||||
return 1
|
||||
|
||||
print(f"Prüfe Ihre Website {cfg['target']} ...")
|
||||
pages, errors = _crawl_and_extract(cfg)
|
||||
bm = BaselineManager(cfg["data_dir"])
|
||||
|
|
@ -813,6 +832,12 @@ def cmd_scan(args: argparse.Namespace, cfg: dict) -> int:
|
|||
_print_summary(assessment, diff, cloak_diff, asset_diff, ext_links, ai_result, cfg["target"],
|
||||
config_path=getattr(args, "config", None))
|
||||
send_alert(report, cfg)
|
||||
|
||||
# --- Lock freigeben ---
|
||||
if lock_fd:
|
||||
fcntl.flock(lock_fd, fcntl.LOCK_UN)
|
||||
lock_fd.close()
|
||||
|
||||
return assessment["exit_code"]
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -163,14 +163,16 @@ class ModelRouter:
|
|||
|
||||
def refresh_catalog(self) -> None:
|
||||
"""OpenRouter /models + lokale Server /models ziehen (24 h gecacht).
|
||||
Failsafe: blockiert nie."""
|
||||
Failsafe: blockiert nie. Thread-safe via self._lock."""
|
||||
if not self._refresh:
|
||||
return
|
||||
fetched_at = self._catalog.get("fetched_at")
|
||||
slugs = self._catalog.get("slugs") or []
|
||||
servers = self._catalog.get("servers") or {}
|
||||
if fetched_at and (slugs or servers) and (time.time() - fetched_at) < 86400:
|
||||
return # Cache frisch
|
||||
# Cache-Check unter Lock — vermeidet doppelte Fetches bei parallelen Scans
|
||||
with self._lock:
|
||||
fetched_at = self._catalog.get("fetched_at")
|
||||
slugs = self._catalog.get("slugs") or []
|
||||
servers = self._catalog.get("servers") or {}
|
||||
if fetched_at and (slugs or servers) and (time.time() - fetched_at) < 86400:
|
||||
return # Cache frisch
|
||||
|
||||
new_slugs, new_servers = [], {}
|
||||
# 1. OpenRouter-Katalog (primär)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue