1. transaction.on_commit()
¿Qué es?
Es un método de registro de callback que se utiliza en Django cuando se quiere ejecutar alguna acción justo después de que una transacción de base de datos haya sido exitosa.
from django.db import transaction
transaction.on_commit(my_function)
Cuando se ejecuta este código, my_function()
se ejecuta después de que la transacción actual haya finalizado exitosamente.
2. ¿Cuándo se utiliza?
Situación | ¿Uso adecuado? |
---|---|
Cuando se desea ejecutar algo después de que se haya confirmado el almacenamiento en DB | ✅ Adecuado |
Cuando se desea ejecutar una tarea de Celery después de la transacción | ✅ Adecuado |
Llamadas a API externas, actualizaciones de caché, etc. | ✅ Adecuado |
Cuando el orden de la llamada no es importante fuera de la transacción | ❌ Inadecuado |
3. Conceptos clave
on_commit()
solo tiene sentido "cuando hay una transacción en curso".- Si no hay transacción, ¡el callback se ejecutará de inmediato!
4. Ejemplo incorrecto
def my_view(request):
def notify():
print("¡Ejecutado!")
transaction.on_commit(notify) # ¡Se ejecuta inmediatamente debido a que no hay transacción!
5. Ejemplo de uso correcto
from django.db import transaction
def my_view(request):
with transaction.atomic():
post = Post.objects.create(...)
post.categories.add(...)
def translate():
translate_post.delay(post.id)
transaction.on_commit(translate)
En el ejemplo anterior, translate()
solo se ejecutará después de que se haya completado la creación del post
y la adición de las categorías.
6. ¿Por qué es importante?
Muchos desarrolladores confunden lo siguiente:
create()
yadd()
de ORM no se han confirmado realmente- Antes de la confirmación, todo está en estado de "almacenamiento lógico"
- Las tareas de Celery se ejecutan en un proceso separado, por lo que,
- Si se ejecutan antes de la confirmación, se hará referencia a datos incompletos
7. Ejemplo ideal usando Celery
@shared_task
def post_finalize_task(post_id, categories, tags):
post = Post.objects.get(id=post_id)
with transaction.atomic():
for name in categories:
cat, _ = Category.objects.get_or_create(name=name)
post.categories.add(cat)
for name in tags:
tag, _ = Tag.objects.get_or_create(name=name)
post.tags.add(tag)
def schedule_translation():
translate_post.delay(post.id)
transaction.on_commit(schedule_translation)
Esta estructura garantiza que la tarea translate_post
solo se ejecute una vez que el almacenamiento de categorías/etiquetas esté confirmado.
8. Resumen
Concepto | Descripción |
---|---|
¿Cuándo se ejecuta? | Inmediatamente después de que la transacción se haya confirmado con éxito |
¿Y si falla? | No se ejecuta nunca si se realiza un rollback |
¿Sin transacción? | Se ejecuta de inmediato (¡cuidado!) |
¿Dónde usarlo? | Dentro del bloque with transaction.atomic() |
Ejemplos de uso | Ejecutar tareas de Celery, enviar notificaciones, aplicar cachés, etc. |
9. Comentario de Jesse
transaction.on_commit()
no es solo una ejecución retrasada.
Es una expresión clara de la intención del desarrollador de ejecutar solo si la transacción ha sido exitosa, y
Es una herramienta esencial para mantener la integridad de los datos al usar ORM y procesamiento asíncrono juntos.
Add a New Comment