在Django应用程序中使用Celery任务中的事务会导致问题吗?

时间:2012-10-18 11:41:39

标签: python django transactions celery django-celery

我写了一套芹菜任务。这些任务中的每一个都只需要一个例子 - 作者id作为参数,对于作者的每本书,它都会获取最新的价格并将其存储在数据库中。

我想通过将Django的 @transaction.commit_on_success装饰器添加到我的任务中来为我的任务添加事务。如果任何任务崩溃,我希望整个任务失败,没有任何东西可以保存到数据库中。

我有十几个芹菜工人检查作者的书籍价格,我想知道这个简单的交易逻辑是否会导致我的Postgres数据库中出现锁定和竞争条件。

我已经挖掘过并发现这个名为django-celery-transactions的项目,但我仍然没有理解这背后的真正问题以及该项目试图解决的问题。

2 个答案:

答案 0 :(得分:1)

原因是在Django视图中,如果应用装饰器,则在视图退出之前不会提交数据库事务。在视图返回并触发提交之前,您可以调用期望已经提交数据库事务的任务,即这些条目存在于DB上下文中。

为了防范这种竞争条件(任务在您的视图开始并因此完成交易),您可以手动管理它或使用您提到的自动处理它的模块。

例如,在您的案例中可能失败的示例是,如果您要添加新作者,并且您有一个任务可以获取其所有/任何图书的价格。如果任务在新作者事务的提交完成之前执行,那么您的任务将尝试使用尚不存在的id来获取Author。

答案 1 :(得分:1)

这取决于几个方面,包括:数据库的事务隔离级别,检查价格更新的频率以及预期价格变化的频率。例如,如果您每秒向stock standard PostgreSQL进行大量更新,则在事务中多次执行相同的select语句可能会得到不同的结果。

数据库经过优化以处理并发性,所以我不认为这对您来说是一个问题;特别是如果您在获取价格之前不打开交易(即使用上下文管理器而不是装饰任务)。如果 - 由于某种原因 - 将来事情变得缓慢,然后优化(不那么频繁地取价,调整数据库配置等)。

至于你的其他问题:django-celery-transactions旨在防止Django和Celery之间的竞争条件。例如,如果您要将新创建的对象的主键传递给任务:任务可能会在提交视图事务之前尝试检索该对象。吊杆!