我对交易和芹菜任务有疑问。所以当然,如果你有一个交易和一个芹菜任务访问同一个表/记录我们就会遇到竞争条件,这对我来说并不神秘。
但是,请考虑以下代码:
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事务。
但是,在运行芹菜任务时,未设置字段field_a
。
我的问题:
由于我们在创建任务之前提交了,是否仍然存在竞争条件?
其他信息
我们正在使用Postgres版本9.1
每个事务都使用READ COMMITTED隔离级别
在已设置引擎dowant.lib.db.backends.postgresql_psycopg2_debugger
field_a
的其他数据库上,任务按预期工作。使用引擎dowant.lib.db.backends.postgresql_psycopg2_hstore_ready
时会出现所描述的问题(不确定它是否与引擎相关)。
芹菜版本为2.2
我尝试了不同的数据库。除了发动机改变之外,仍然是相同的行为。所以这就是我提到这一点的原因。
非常感谢。
答案 0 :(得分:1)
尝试在self.__class__.objects.select_for_update().get(pk=self.pk)
之前添加save
,看看会发生什么。
它应该阻止对该行的所有读取,直到完成提交。
答案 1 :(得分:1)
这很晚了,但是自Django 1.9起
transaction.on_commit(lambda: enqueue_atask()))