"""Проверка пунктов прожарки на текущем коде (до патчей). Только чтение, ничего не пишет в базу.""" import gc import json import os import re import sys import threading import time from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) os.environ.setdefault("PYTHONIOENCODING", "utf-8") import psutil # noqa: E402 ROOT = Path(__file__).resolve().parent.parent OUT = {} def p(k, v): OUT[k] = v print(f"{k}: {v}") # 2. валидация limit: эмулируем то, что делает serve для /api/items def check_limit(): def parse(raw): try: return min(int(raw), 200) except ValueError as e: return f"ValueError: {e}" p("limit[-1]", parse("-1")) p("limit[abc]", parse("abc")) p("limit[999999]", parse("999999")) # 3. утечка соединений def check_conn_leak(): from omni import store gc.collect() before = len(psutil.Process().open_files()) for _ in range(50): store.top(limit=1) gc.collect() after = len(psutil.Process().open_files()) p("fd_before", before) p("fd_after_50_calls", after) p("fd_leak", after - before) # 4. троттлинг def check_throttle(): from omni import net net._cfg["per_host_delay"] = 0.3 net._last.clear() t0 = time.time() threads = [threading.Thread(target=lambda: [net._throttle("example.org") for _ in range(3)]) for _ in range(8)] for t in threads: t.start() for t in threads: t.join() el = time.time() - t0 expected = 0.3 * (8 * 3 - 1) p("throttle_elapsed", round(el, 2)) p("throttle_expected_min", round(expected, 2)) p("throttle_broken", el < expected * 0.5) # 6. мёртвые файлы def check_dead(): names = ["abuse_sources", "rank", "sources_abuse"] for n in names: hits = [] for f in (ROOT / "omni").glob("*.py"): if f.stem == n: continue txt = f.read_text(encoding="utf-8", errors="replace") if re.search(rf"(import|from)\s+.*\b{n}\b", txt): hits.append(f.name) p(f"imports_{n}", hits) # 7. дубли источников def check_dupe_sources(): from omni import sources urls = [s.url for s in sources.all_sources()] p("sources_total", len(urls)) p("urls_unique", len(set(urls))) p("dupe_groups", len(urls) - len(set(urls))) # 8. except Exception def check_except(): total = 0 for f in (ROOT / "omni").rglob("*.py"): total += len(re.findall(r"except\s+Exception", f.read_text(encoding="utf-8", errors="replace"))) p("except_exception_total", total) # 9. JOBS без eviction def check_jobs(): from omni import serve src = (ROOT / "omni" / "serve.py").read_text(encoding="utf-8") p("jobs_has_eviction", "JOBS.pop" in src or "del JOBS" in src) for i in range(500): serve._job(f"j{i}", status="done") p("jobs_len_after_500", len(serve.JOBS)) # 10. sleep в ai.py def check_ai_sleep(): src = (ROOT / "omni" / "ai.py").read_text(encoding="utf-8") m = re.search(r"except Exception:\s*\n\s*time\.sleep\(([^)]*)\)", src) p("ai_sleep_line", m.group(0).replace("\n", " ") if m else None) # 1. /run в боте def check_bot_run(): src = (ROOT / "omni" / "bot.py").read_text(encoding="utf-8") p("bot_new_plus_equals_add", "new += store.add(items)" in src) p("bot_cmd_abuse_present", "def cmd_abuse" in src) p("bot_cmds_abuse_present", "cmd_abuse" in src) if __name__ == "__main__": import contextlib import io check_limit() with contextlib.redirect_stdout(io.StringIO()): check_bot_run() check_bot_run() check_throttle() check_dead() check_dupe_sources() check_except() with contextlib.redirect_stderr(io.StringIO()): check_jobs() check_ai_sleep() check_conn_leak() print("\nJSON:", json.dumps(OUT, ensure_ascii=False, default=str))