asyncio : les rĂšgles de survie du projet
Pourquoi l'app est async de bout en bout
Une requĂȘte copilot passe des secondes Ă attendre : le LLM gĂ©nĂšre, Postgres rĂ©pond, Cohere rerank. En sync, chaque requĂȘte bloquerait un worker entier. En async, l'attente libĂšre l'event loop : un seul process sert des dizaines de conversations simultanĂ©es. D'oĂč la rĂšgle du projet : SDK LLM en version Async*, SQLAlchemy async, et jamais un appel bloquant nu dans un handler.
Les trois gestes Ă maĂźtriser
1. asyncio.to_thread : mettre le sync en quarantaine
Une lib sync (parsing PDF, un client legacy) gĂšle toute l'app si on l'appelle directement. Le projet l'exile dans un thread :
tables = await asyncio.to_thread(pdfplumber_extract, pdf_bytes) # l'event loop respire
2. asyncio.gather : paralléliser les attentes indépendantes
# Les 4 sources de la recherche hybride (module 3) partent EN MĂME TEMPS :
exact, fts, trgm, vec = await asyncio.gather(
search_exact(q), search_fulltext(q), search_trigram(q), search_vector(q),
)
Quatre requĂȘtes de 50 ms sĂ©quentielles = 200 ms ; en gather = ~50 ms. C'est aussi comme ça que l'agent exĂ©cute plusieurs tool calls d'un mĂȘme tour en parallĂšle.
3. asyncio.create_task : le vrai arriĂšre-plan
Une extraction dure 30 s â la requĂȘte HTTP ne peut pas attendre. Le projet rĂ©pond 202 avec un job_id et lance asyncio.create_task(run_pipeline(...)). Deux obligations qui vont avec : garder une rĂ©fĂ©rence Ă la task (sinon le GC peut la tuer en plein vol) et persister le job (store Postgres + boucle de rĂ©conciliation) pour survivre Ă un redĂ©marrage â une task in-process n'est PAS une queue durable.
L'erreur qui coûte cher : le blocage caché
time.sleep, requests.get, un pandas.read_excel de 80 Mo directement dans un handler async : tout le monde attend (chaque conversation, chaque SSE). SymptĂŽme en prod : latences qui montent partout d'un coup, sans CPU. RĂ©flexe de debug : chercher l'appel sync â c'est exactement ce que traque la rĂšgle ASYNC de ruff activĂ©e sur le projet.
Un parseur PDF sync appelĂ© nu dans un handler asyncâŠ