Audit: ThreadPoolExecutor avec parallel borne (evite saturation DB/PSMP)

This commit is contained in:
Pierre & Lumière 2026-04-15 00:20:12 +02:00
parent 48efb07b49
commit 3c4244597c
2 changed files with 9 additions and 11 deletions

View File

@ -181,8 +181,8 @@ async def audit_global(request: Request, db=Depends(get_db)):
if not hostnames:
return RedirectResponse(url="/audit?msg=no_hosts", status_code=303)
# Lancer en arrière-plan
job_id = start_audit_job(hostnames)
# Lancer en arrière-plan avec parallelisme configure
job_id = start_audit_job(hostnames, parallel=parallel)
return RedirectResponse(url=f"/audit/realtime/progress/{job_id}", status_code=303)

View File

@ -323,8 +323,9 @@ import time as _time
_audit_jobs = {}
def start_audit_job(hostnames):
"""Lance un audit en arriere-plan. Retourne le job_id."""
def start_audit_job(hostnames, parallel=3):
"""Lance un audit en arriere-plan avec pool de threads borne. Retourne le job_id."""
from concurrent.futures import ThreadPoolExecutor
job_id = str(uuid.uuid4())[:8]
job = {
"id": job_id,
@ -334,19 +335,16 @@ def start_audit_job(hostnames):
"servers": {},
"results": [],
"finished": False,
"parallel": parallel,
}
for hn in hostnames:
job["servers"][hn] = {"hostname": hn, "stage": "pending", "detail": "En attente", "status": None}
_audit_jobs[job_id] = job
def _run():
threads = []
for hn in hostnames:
t = threading.Thread(target=_audit_one, args=(job, hn.strip()), daemon=True)
threads.append(t)
t.start()
for t in threads:
t.join()
with ThreadPoolExecutor(max_workers=max(1, int(parallel))) as pool:
for hn in hostnames:
pool.submit(_audit_one, job, hn.strip())
job["finished"] = True
job["finished_at"] = _time.time()