在 Django Admin 中保存新对象并发送到 Celery 任务后,匹配查询不存在

Posted

技术标签:

【中文标题】在 Django Admin 中保存新对象并发送到 Celery 任务后,匹配查询不存在【英文标题】:Matching query doesn't exist after a new object save in Django Admin and sent to Celery task 【发布时间】:2015-09-07 03:47:28 【问题描述】:

我在 Django Admin (Django 1.8) 中保存一个对象并将它们传递给 Celery Task。不幸的是,我得到了一个错误[有时!]:“匹配的查询不存在”。我知道这是事务的问题,但解决该问题的最佳方法是什么?

class MyModelAdmin(admin.ModelAdmin)
    def save_model(self, request, obj, form, change):
        super(MyAdmin, self).save_model(request, obj, form, change)
        if not change:
            celery_task.delay(obj.pk)

@app.task()
def celery_task(obj_pk):
    MyModel.objects.get(pk=obj_pk)

问题是 Django Admin 中的整个视图位于 transaction.atomic() 块中。有时 celery 运行速度比交易结束时更快。我想知道解决这个问题的最佳方法是什么。我认为在调用 celery_task 时添加 eta 是一个令人毛骨悚然的想法(或者可能不是?) - celery_task.apply_async((obj.pk,), eta=+10 seconds)

【问题讨论】:

在这方面也许有一些有趣的链接:集成post commit hooks 的票被接受(并且还有一个指向 contrib 包的链接)。在此之前,我认为eta 以及配置重试间隔似乎并不是一个令人毛骨悚然的想法(但对其他观点感到好奇)。至少它保持简单的方式。否则,您还可以运行一些独立的作业,每隔 X 间隔检查数据库是否有新更改,并从那里触发任务。 为什么不尝试在post_save 信号上调用 celery 任务? @argaen post_save 在事务块中也被调用。 【参考方案1】:

我认为eta 是个好主意。但是竞态条件的可能性仍然存在,因此您可以使用eta retry a task 进行故障转移:

@app.task(default_retry_delay=60, max_retries=3)  # retry in 1 minute with maximum 3 retries
def celery_task(obj_pk):
    try:
        MyModel.objects.get(pk=obj_pk)
    except MyModel.DoesNotExist, exc:
        celery_task.retry(exc=exc)

【讨论】:

以上是关于在 Django Admin 中保存新对象并发送到 Celery 任务后,匹配查询不存在的主要内容,如果未能解决你的问题,请参考以下文章

向Django Admin添加键盘快捷键功能

Django Admin,保存时调用函数

防止 Django 在并发请求时将同一个对象多次保存到数据库中

Django-Admin TabularInline 在保存前修改内联项属性

Django Admin Cookbook-40如何为Django Admin覆盖保存操作

在 Django 中通过 admin 生成的表单