【问题标题】:Django-celery task and django transactionDjango-celery 任务和 django 事务
【发布时间】:2012-09-06 10:37:12
【问题描述】:

我有一个关于交易和 celery 任务的问题。所以对我来说,当然,如果你有一个事务和一个 celery 任务访问同一个表/记录,我们就会有一个竞争条件,这对我来说并不神秘。

但是,请考虑以下代码:

def f(self):
   # function of module that inherits from models.Model
   self.field_a = datetime.now()

   self.save()
   transaction.commit_unless_managed()

   # depending on the configuration of this module
   # this might return None or a datetime object.
   eta = self.get_task_eta()

   if eta:
       celery_task_do_something.apply_async(args=(self.pk, self.__class__),
                                            eta=eta)
   else:
       celery_task_do_something.delay(self.pk, self.__class__)

这是芹菜任务:

def celery_task_do_something(pk, cls):

    o = cls.objects.get(pk=pk)

    if o.field_a:
        # perform something
        return True
    return False

如您所见,在创建任务之前,我们调用 transaction.commit_unless_managed 并且它应该提交,因为 django 事务当前不受管理。

但是,当运行 celery 任务时,字段 field_a 没有设置。

我的问题

既然我们在创建任务之前就进行了提交,是否还有可能存在竞争条件?

其他信息

  • 我们使用的是 Postgres 9.1 版

  • 每个事务都以 READ COMMITTED 隔离级别运行

  • 在具有引擎dowant.lib.db.backends.postgresql_psycopg2_debugger field_a 的不同数据库上已设置并且任务按预期工作。使用引擎dowant.lib.db.backends.postgresql_psycopg2_hstore_ready 会出现所描述的问题(不确定它是否与引擎有关)。

  • Celery 版本为 2.2

  • 我尝试了不同的数据库。仍然是相同的行为,除非引擎发生变化。所以这就是我提到这个的原因。

非常感谢。

【问题讨论】:

  • transaction.commit_unless_managed()之前应该有一个self.save()吗?
  • 好的,事实上有。很抱歉。

标签: django celery postgresql-9.1 django-celery


【解决方案1】:

这是迟到了,但从 django 1.9 开始

transaction.on_commit(lambda: enqueue_atask()))

【讨论】:

    【解决方案2】:

    尝试在save 之前添加self.__class__.objects.select_for_update().get(pk=self.pk),看看会发生什么。

    它应该阻止对该行的所有读取,直到提交完成。

    【讨论】: