1. Situación: ¿on_commit() se ejecuta demasiado rápido?
Recientemente, en un proyecto de Django, he configurado transaction.on_commit()
para que
los trabajos de Celery se ejecuten después de que la transacción haya sido exitosa.
Sin embargo, al revisar los registros, noté un fenómeno extraño.
Aún no se habían completado tareas como
post.categories.add(...)
pero,
la tarea de Celery dentro deon_commit()
se estaba ejecutando.
2. Al revisar el código…
def view():
post = Post.objects.create(...)
def post_process():
with transaction.atomic():
post.categories.add(...)
post.tags.add(...)
def run_async():
translate_post.delay(post.id)
transaction.on_commit(run_async)
threading.Thread(target=post_process).start()
Al principio no parecía haber ningún problema…
pero esta threading.Thread()
era la trampa.
3. Causa: Las transacciones son locales del hilo
Las transacciones de Django son dependientes del hilo actual.
Es decir, transaction.atomic()
y on_commit()
se aplican solo a la transacción abierta en este hilo.
La
transaction.atomic()
abierta en un hilo nuevo
no tiene relación alguna con la transacción principal.
4. Lo que sucedió como resultado
- La tarea de Celery se ejecutó "después de la confirmación de la transacción", pero
- esa transacción era solo una pequeña transacción dentro de un subhilo
- y tareas como
post.categories.add(...)
aún estaban en proceso
Es decir, Celery se ejecutó demasiado rápido para lo que se pretendía,
y surgió el problema de acceder a datos incompletos.
5. Solución
Simplemente se puede corregir de esta manera:
def view():
post = Post.objects.create(...)
with transaction.atomic():
post.categories.add(...)
post.tags.add(...)
def run_async():
translate_post.delay(post.id)
transaction.on_commit(run_async)
🚫 threading.Thread(...)
✅ Solo registrar on_commit()
en el hilo principal
6. Resumen
- Las transacciones de Django son locales del hilo
on_commit()
se ejecuta solo después de la confirmación de la transacción del hilo actual- Si se registra en otro hilo, solo responderá a la transacción de ese hilo
Esta experiencia ha sido una lección poderosa.
Me di cuenta de que cuando se usan transacciones + Celery + hilos,
es crucial tener mucho cuidado.
Add a New Comment