互联网上的许多地方都说,必须确保如果从django模型实例传递主键,则传递给它们的任务仅在当前上下文中的事务完成后才开始。您可以使用Django的transaction.on_commit
来做到这一点。否则,您会经常在被调用的任务中遇到ObjectDoesNotExist
错误。
我一直在使用其画布基元(chain
,chord
,group
,...)开发一些轻度复杂的celery工作流程,其中调用中间任务(例如,下一个链中的任务)是由celery自己完成的,而我一直在处理此类错误,因为其中一个流程涉及将这样的主键传递给链中的下一个任务。我找不到确保当前任务中的事务完成后才调用下一个任务的任何方法。
我试图关闭自动提交功能,并自己处理提交和回滚:
transaction.set_autocommit(False)
try:
stuff_to_get = Model.objects.first()
try:
data = very_long_running_query()
except ConnectionReset as exc:
self.retry(exc=exc)
obj = Foo.objects.create(**data) # this is then referred to in a task further in the chain
return obj.pk
except Exception as e:
transaction.rollback()
raise e
else:
transaction.commit()
finally:
transaction.set_autocommit(True)
但这会在第一次django.db.utils.ProgrammingError: set_session cannot be used inside a transaction
调用中导致postgres产生奇怪的set_autocommit
错误。
我非常清楚,我不确定我在这里处理事务的方式,因此最后一个错误可能很难解决,但是我不确定这意味着什么。 Postgres是否说我已经在交易中了?最初,此策略是否是一个好主意(长时间运行的事务是否有任何危害?查询可持续长达50秒)。或者...还有另一种方法可以确保交易在调用其他任何内容之前完成?
(PS:不是我正在使用数据库将芹菜任务的结果传递到下一个任务,而是将一个对象存储在一个任务中,然后在下一个任务中运行一个运行时间很长的查询以获取一些内容必须用该对象的外键存储的东西)