הדף הציג את התורים באופן לא-אחיד (by_status גולמי), בלי הבחנה בין "ממתין"
(בקלוג: status=pending) ל"בתור" (התור הפעיל: requested_at IS NOT NULL), בלי
הצגת הפריט שרץ כרגע, ובלי שום שליטה בתהליכים.
מה נוסף:
1. כרטיסי-תור אחידים — בתור / ממתין(בקלוג) / בעיבוד / הושלם / נכשל + "רץ עכשיו"
(citation/case_number של הפריט בעיבוד) לכל drain (אחזור-פסיקה, מטא-דאטה,
הלכות, יומונים). שערי-אנוש (אישור-הלכות, פסיקה-חסרה) נשארים מוני-סטטוס.
2. פאנל ניהול-תהליכים בסגנון "שירותי Windows":
- דמון (court-fetch-service/xvfb/chat/reaper): הפעל-מחדש / עצור / הפעל.
- cron drain: "הרץ עכשיו" (pm2 restart) + מתג הפעל/כבה תזמון.
3. כל תגי-הסטטוס מתורגמים לעברית.
מנגנון:
- הפעל/כבה תזמון = דגל ב-DB (טבלה drain_controls). pm2 cron_restart מחיה תהליך
שעוצר ב-stop, לכן ה"כיבוי" האמין הוא דגל שכל drain בודק ב-startup (no-op מיידי
כשכבוי). הקונטיינר כותב/קורא ישירות מ-DB.
- הרץ-עכשיו + restart/stop/start = proxy ל-pm2 דרך endpoint חדש בגשר-המארח
(court_fetch_service /pm2/control), מאובטח Bearer + whitelist ל-legal-* בלבד.
- יומונים: drain_digests הועבר מ-crontab ל-pm2 (legal-digest-drain.config.cjs)
כדי שיופיע ויהיה שליט כמו כל drain. drain_halacha_queue.py הובא לבקרת-גרסאות.
Invariants: מקיים G2 (הרחבת /operations + הגשר הקיים, לא מסלול מקביל) ו-G1
(drain_controls = מקור-אמת יחיד לכיבוי, נורמליזציה במקור ולא תיקון-בקריאה).
אין בליעת שגיאות שקטה (הגשר מחזיר {ok,error}; המוטציות מציגות toast).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
55 lines
2.0 KiB
Python
55 lines
2.0 KiB
Python
"""Drain the precedent metadata-extraction queue.
|
|
|
|
Calls ``process_pending_extractions(kind='metadata')`` in batches until the
|
|
queue is empty (two consecutive zero-progress rounds). Metadata extraction runs
|
|
on **Gemini Flash** (structured JSON) — fast and reliable, unlike the agentic
|
|
claude CLI which hit ``error_max_turns`` on this bounded task. A no-op (fast)
|
|
when the queue is empty.
|
|
|
|
Host-only (reads GEMINI_API_KEY + POSTGRES_URL from ~/.env via legal_mcp.config).
|
|
Scheduled by ``legal-metadata-drain`` (pm2 cron); also runnable by hand:
|
|
|
|
mcp-server/.venv/bin/python scripts/drain_metadata_queue.py [batch]
|
|
"""
|
|
|
|
import asyncio
|
|
import os
|
|
import sys
|
|
|
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "mcp-server", "src"))
|
|
|
|
from legal_mcp.services import db
|
|
from legal_mcp.services import precedent_library as pl
|
|
|
|
|
|
async def main() -> int:
|
|
# /operations "disable" switch — no-op immediately if turned off (pm2
|
|
# cron_restart can still fire a stopped job, so the gate lives in the DB).
|
|
if await db.is_drain_disabled("legal-metadata-drain"):
|
|
print("===SKIP=== legal-metadata-drain disabled via /operations", flush=True)
|
|
return 0
|
|
batch = int(sys.argv[1]) if len(sys.argv) > 1 else 10
|
|
total = 0
|
|
empty_rounds = 0
|
|
rnd = 0
|
|
while empty_rounds < 2:
|
|
rnd += 1
|
|
out = await pl.process_pending_extractions(kind="metadata", limit=batch)
|
|
processed = out.get("processed", 0)
|
|
total += processed
|
|
print(f"[round {rnd}] processed={processed} total_pending={out.get('total_pending', 0)} "
|
|
f"status={out.get('status')}", flush=True)
|
|
for r in out.get("results", []):
|
|
print(f" {str(r.get('case_number',''))[:42]}: {r.get('status')}", flush=True)
|
|
if processed == 0:
|
|
empty_rounds += 1
|
|
await asyncio.sleep(3)
|
|
else:
|
|
empty_rounds = 0
|
|
print(f"===DONE=== metadata extracted (cumulative cases handled={total})", flush=True)
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(asyncio.run(main()))
|