PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Céleri et transaction.atomic

Comme @dotz mentionné , il n'est guère utile de générer une tâche asynchrone et de la bloquer immédiatement et de continuer à attendre jusqu'à ce qu'elle se termine.

De plus, si vous l'attachez de cette façon (le .get() à la fin), vous pouvez être sûr que le mymodel les changements d'instance qui viennent d'être effectués ne seront pas vus par votre travailleur car ils ne seront pas encore validés - rappelez-vous que vous êtes toujours à l'intérieur du atomic bloquer.

Ce que vous pourriez faire à la place (à partir de Django 1.9) est de retarder la tâche jusqu'à ce que la transaction active actuelle soit validée, en utilisant django.db.transaction.on_commit crochet :

from django.db import transaction

with transaction.atomic():
    mymodel.save()
    transaction.on_commit(lambda:
        mytask.delay(mymodel.id))

J'utilise ce modèle assez souvent dans mon post_save des gestionnaires de signaux qui déclenchent le traitement de nouvelles instances de modèle. Par exemple :

from django.db import transaction
from django.db.models.signals import post_save
from django.dispatch import receiver
from . import models   # Your models defining some Order model
from . import tasks   # Your tasks defining a routine to process new instances

@receiver(post_save, sender=models.Order)
def new_order_callback(sender, instance, created, **kwargs):
    """ Automatically triggers processing of a new Order. """
    if created:
        transaction.on_commit(lambda:
            tasks.process_new_order.delay(instance.pk))

De cette façon, cependant, votre tâche ne sera pas exécutée si la transaction de base de données échoue. C'est généralement le comportement souhaité, mais gardez-le à l'esprit.

Modifier  :Il est en fait plus agréable d'enregistrer la tâche de céleri on_commit de cette façon (sans lambda) :

transaction.on_commit(tasks.process_new_order.s(instance.pk).delay)