fix(qualys/duplicates): scan async (background thread) + bandeau scan en cours - evite 503 HAProxy

This commit is contained in:
Pierre & Lumière 2026-04-25 10:31:07 +00:00
parent e832381b68
commit cc550c2d84
2 changed files with 42 additions and 7 deletions

View File

@ -1299,20 +1299,43 @@ async def qualys_dashboard_history(request: Request, db=Depends(get_db),
# === DOUBLONS QUALYS === # === DOUBLONS QUALYS ===
_dupes_scan_running = False
@router.get("/qualys/duplicates", response_class=HTMLResponse) @router.get("/qualys/duplicates", response_class=HTMLResponse)
async def qualys_duplicates(request: Request, db=Depends(get_db), async def qualys_duplicates(request: Request, db=Depends(get_db),
refresh: int = 0): refresh: int = 0):
global _dupes_scan_running
user = get_current_user(request) user = get_current_user(request)
if not user: if not user:
return RedirectResponse(url="/login") return RedirectResponse(url="/login")
perms = get_user_perms(db, user) perms = get_user_perms(db, user)
if not can_view(perms, "qualys"): if not can_view(perms, "qualys"):
return RedirectResponse(url="/dashboard") return RedirectResponse(url="/dashboard")
from app.services.qualys_service import find_duplicate_hostnames from app.services.qualys_service import find_duplicate_hostnames, _cache
data = find_duplicate_hostnames(db, force_refresh=bool(refresh)) if refresh:
_cache.delete("qualys:duplicates")
cached = _cache.get("qualys:duplicates")
if cached is None and not _dupes_scan_running:
_dupes_scan_running = True
import threading
def _runner():
global _dupes_scan_running
try:
from app.database import SessionLocal
ss = SessionLocal()
try:
find_duplicate_hostnames(ss, force_refresh=True)
finally:
ss.close()
finally:
_dupes_scan_running = False
threading.Thread(target=_runner, daemon=True).start()
ctx = base_context(request, db, user) ctx = base_context(request, db, user)
ctx.update({"dupes_data": data, ctx.update({"dupes_data": cached or {"total_assets": 0, "duplicate_hostnames": 0,
"can_delete": can_edit(perms, "qualys")}) "total_zombies": 0, "items": []},
"can_delete": can_edit(perms, "qualys"),
"scan_running": _dupes_scan_running and cached is None,
"from_cache": cached is not None})
return templates.TemplateResponse("qualys_duplicates.html", ctx) return templates.TemplateResponse("qualys_duplicates.html", ctx)

View File

@ -3,11 +3,23 @@
{% block content %} {% block content %}
<div class="flex justify-between items-center mb-4"> <div class="flex justify-between items-center mb-4">
<h2 class="text-xl font-bold text-cyber-accent">Doublons Qualys (assets zombies)</h2> <h2 class="text-xl font-bold text-cyber-accent">Doublons Qualys (serveurs uniquement)</h2>
<a href="/qualys/duplicates?refresh=1" class="btn-sm bg-cyber-border text-cyber-accent" <a href="/qualys/duplicates?refresh=1" class="btn-sm bg-cyber-border text-cyber-accent">🔄 Re-scan API</a>
data-loading="Scan complet API Qualys...|Recuperation des ~6000 assets, peut prendre 3 a 5 minutes">🔄 Re-scan API</a>
</div> </div>
{% if scan_running %}
<div class="card p-4 mb-4 border-2 border-cyber-accent flex items-center gap-4" style="background:linear-gradient(90deg,#00334d,#003355);box-shadow:0 0 20px rgba(0,212,255,.3)">
<div style="border:4px solid rgba(0,212,255,.2); border-top:4px solid #00d4ff; border-radius:50%; width:42px; height:42px; animation:spin 0.9s linear infinite; flex-shrink:0"></div>
<div class="flex-1">
<div class="text-cyber-accent font-bold text-base">Scan API Qualys en cours...</div>
<div class="text-xs text-gray-400 mt-1">Recuperation de tous les assets via API (~6000), durée typique 2 à 4 minutes. La page se rafraîchira automatiquement.</div>
</div>
</div>
<script>setTimeout(function() { window.location.href = '/qualys/duplicates'; }, 15000);</script>
{% elif from_cache %}
<div class="text-xs text-gray-500 mb-2">Données du cache (TTL 10min). Re-scan pour forcer.</div>
{% endif %}
<div class="grid grid-cols-3 gap-3 mb-4"> <div class="grid grid-cols-3 gap-3 mb-4">
<div class="card p-3 border-cyber-accent"> <div class="card p-3 border-cyber-accent">
<div class="text-xs text-gray-500 uppercase">Total assets Qualys</div> <div class="text-xs text-gray-500 uppercase">Total assets Qualys</div>