fix(qualys/dashboard): insert pending row dans la route avant spawn thread (no race)

This commit is contained in:
Pierre & Lumière 2026-04-25 00:07:22 +00:00
parent daf87891a7
commit 9a7f446637
2 changed files with 17 additions and 12 deletions

View File

@ -1219,15 +1219,20 @@ async def qualys_dashboard_refresh(request: Request, db=Depends(get_db)):
WHERE status='pending' AND run_at > now() - interval '15 minutes' LIMIT 1""")).fetchone() WHERE status='pending' AND run_at > now() - interval '15 minutes' LIMIT 1""")).fetchone()
if pending: if pending:
return RedirectResponse(url="/qualys/dashboard?msg=already_running", status_code=303) return RedirectResponse(url="/qualys/dashboard?msg=already_running", status_code=303)
# Insert pending immediatement (route, pas thread) pour eviter race condition
run_id = db.execute(text("""INSERT INTO qualys_vuln_snapshot_run (status, triggered_by)
VALUES ('pending', :tb) RETURNING id"""),
{"tb": f"manual:{user.username}"}).scalar()
db.commit()
import threading import threading
def _runner(): def _runner(rid):
from app.database import SessionLocal from app.database import SessionLocal
s = SessionLocal() s = SessionLocal()
try: try:
compute_vuln_dashboard(s, triggered_by=f"manual:{user.username}") compute_vuln_dashboard(s, triggered_by=f"manual:{user.username}", run_id=rid)
finally: finally:
s.close() s.close()
threading.Thread(target=_runner, daemon=True).start() threading.Thread(target=_runner, args=(run_id,), daemon=True).start()
return RedirectResponse(url="/qualys/dashboard?msg=refresh_started", status_code=303) return RedirectResponse(url="/qualys/dashboard?msg=refresh_started", status_code=303)

View File

@ -889,8 +889,8 @@ def _is_scanned(asset_row, has_vuln_data):
return True return True
return False return False
def compute_vuln_dashboard(db, triggered_by="manual"): def compute_vuln_dashboard(db, triggered_by="manual", run_id=None):
"""Calcule un nouveau snapshot (insert run + snapshot rows). """Calcule un nouveau snapshot. Si run_id fourni, l'utilise (sinon en cree un).
Retourne dict {ok, msg, run_id, asset_count, duration_sec}.""" Retourne dict {ok, msg, run_id, asset_count, duration_sec}."""
global _dashboard_running global _dashboard_running
if _dashboard_running: if _dashboard_running:
@ -899,14 +899,14 @@ def compute_vuln_dashboard(db, triggered_by="manual"):
_dashboard_running = True _dashboard_running = True
import time import time
t0 = time.time() t0 = time.time()
run_id = None
try: try:
# 1. Creer le run en pending # 1. Creer le run en pending si pas deja fourni
run_id = db.execute(text(""" if run_id is None:
INSERT INTO qualys_vuln_snapshot_run (status, triggered_by) run_id = db.execute(text("""
VALUES ('pending', :tb) RETURNING id INSERT INTO qualys_vuln_snapshot_run (status, triggered_by)
"""), {"tb": triggered_by}).scalar() VALUES ('pending', :tb) RETURNING id
db.commit() """), {"tb": triggered_by}).scalar()
db.commit()
# 2. Charger tous les assets avec leurs tags + domaine AD # 2. Charger tous les assets avec leurs tags + domaine AD
rows = db.execute(text(""" rows = db.execute(text("""