【问题标题】:celery task cannot open a model instance after passing a pk or id to the task after saving it in the django view在将 pk 或 id 保存在 django 视图中后,celery 任务无法打开模型实例
【发布时间】:2013-06-21 09:03:48
【问题描述】:

我有一个 django 视图,它创建一个用户,然后将 user.pk 发送到 celery 任务 (.delay),以便通过电子邮件向用户发送电子邮件并通过一些我不希望的 API 调用将用户添加到邮件列表中风景。

在我保存新的用户实例user.save() 后,我将user.pk 发送到芹菜任务email_user_task.delay(user.pk),但芹菜任务因用户不存在的错误而爆炸。

我尝试在 celery 任务中添加一个 try except 块,并休眠以等待视图完成,这可以工作,但当站点繁忙并尝试使用手动事务提交时会导致其他问题,但我得到了其他问题错误并认为这应该可以工作。

@render_to('signup.html')
def signup(request):
    if request.method == "POST":
        form = SignupForm(request.POST, request=request)
        if form.is_valid():
            new_user = form.save(commit=False)
            new_user.email = form.cleaned_data["email"]
            new_user.fist_name = form.cleaned_data["first_name"]
            new_user.last_name = form.cleaned_data["last_name"]
            new_user.save()
            email_user_task.delay(new_user.pk)  # this cannot get the User from the pk
            HttpResponseRedirect(reverse("signup_complete"))
     else:
         form = SignupForm(request=request)
     return locals()

这个芹菜任务炸了:

@task
def email_user_task(user_pk):
    user = User.objects.get(pk=user_pk)  # this yeilds a User.DoesNotExist error

除非 5 秒还不够,否则我的第一个修复方法有效:

def email_user_task(user_pk):
    try:
        user = User.objects.get(pk=user_pk)
    except User.DoesNotExist:
        import time
        time.sleep(5)
        user = User.objects.get(pk=user_pk)  # this works I'm guessing after the view finishes

我错过了什么?即为什么new_user.save() 在调用 celery 任务之前不写入数据库?

【问题讨论】:

  • 您是否查看了数据库并查看用户是否实际创建?另外,celery 进程和 django 进程实际上是在看同一个数据库吗?
  • 是的,这就是修复添加睡眠的原因。我还在本地禁用并失效了所有缓存以进行测试。
  • 啊,对不起。误读了。你有没有在你的 Django 应用中启用ATOMIC_REQUESTS
  • 我认为 ATOMIC_REQUESTS 仅在 dev django 版本中

标签: database django celery


【解决方案1】:

我遇到了同样的问题,试试这个

@render_to('signup.html')
def signup(request):
    if request.method == "POST":
        form = SignupForm(request.POST, request=request)
        if form.is_valid():
            new_user = form.save(commit=False)
            new_user.email = form.cleaned_data["email"]
            new_user.fist_name = form.cleaned_data["first_name"]
            new_user.last_name = form.cleaned_data["last_name"]
            if new_user.save():
              email_user_task.delay(new_user.pk)  # this cannot get the User from the pk
            HttpResponseRedirect(reverse("signup_complete"))
     else:
         form = SignupForm(request=request)
     return locals()

【讨论】:

  • 这里的new_user模型保存方法是自定义的吗?因为 django 的默认模型保存方法并没有真正返回任何东西。任务真的开始了吗?
【解决方案2】:

由于 User 对象被锁定在视图事务中并且不想弄乱事务以确保在 celery 任务尝试访问它之前将其保存,我将所有相关参数传递给 celery 任务以便它可以射出它的电子邮件。

email_user_task.delay(new_user.first_name, new_user.email)

【讨论】:

    猜你喜欢
    • 2016-08-13
    • 2020-06-19
    • 2022-01-24
    • 1970-01-01
    • 2018-07-03
    • 2021-09-07
    • 2014-03-16
    • 1970-01-01
    • 2018-04-14
    相关资源
    最近更新 更多