
🐍 El gran secreto de asyncio: los tasks empiezan siempre en el mismo orden
Cuando trabajás con workflows durables en Python, necesitás que sean deterministas para poder hacer replay-based recovery. ¿Pero cómo lograrlo si los pasos se ejecutan concurrentemente con asyncio.gather?
🔑 La clave está en el event loop:
asyncioes single-threaded: solo ejecuta una tarea a la vez- Cuando usás
asyncio.gather(coro1, coro2, coro3), las tareas se encolan en orden FIFO - Los tasks empiezan siempre en el mismo orden determinista, aunque su finalización sea impredecible
- Una tarea cede control al event loop solo cuando llama
awaitsobre algo que no está listo
# Este orden de inicio es siempre determinista:
results = await asyncio.gather(step1(), step2(), step3())
# step1 comienza primero, luego step2, luego step3🏗️ Aprovechándolo para workflows durables:
El decorador @Step() de DBOS asigna un ID antes del primer await. Como la asignación ocurre en el orden determinista de inicio, todos los steps tienen IDs consistentes entre ejecuciones → recovery sin problemas.
✅ El modelo single-threaded es en realidad más fácil de razonar que los threads paralelos, porque las tareas solo pueden intercalarse cuando ceden control explícitamente con await.
💡 Explicación en pocas palabras#
Python async parece caótico porque varias tareas corren “al mismo tiempo”. Pero hay una regla oculta: todas las tareas comienzan en el orden en que las creás. Esto permite que sistemas de recuperación ante fallos puedan reproducir exactamente qué pasó y en qué orden, aunque las tareas terminen en momentos distintos.
Más información en el link 👇
