芹菜 - 错误处理和数据存储

时间:2012-12-15 02:29:19

标签: celery django-celery celery-task

我正在努力更好地理解有关Celery中结果和错误的常见策略。

我看到结果有状态/状态,并在需要时存储结果 - 我什么时候才能使用这些数据?是否应该在任务中包含错误处理和数据存储?

以下是一个示例场景,以防有助于更好地理解我的目标:

我有一个地理编码任务,可以对用户地址进行编码。如果任务失败或成功,我想更新数据库中的一个字段,让用户知道。 (错误处理)成功后,我希望将地理编码数据插入数据库(数据存储)

应该采取什么方法?

1 个答案:

答案 0 :(得分:1)

让我先说一下我自己仍然对芹菜的感觉。话虽如此,我对如何解决这个问题有一些普遍的倾向,而且由于没有其他人做出回应,我会试一试。

根据你所写的内容,一个相对简单的(虽然我怀疑是非优化的)解决方案是遵循blog comment spam task example from the documentation的广泛轮廓。

<强> app.models.py

class Address(models.Model):

  GEOCODE_STATUS_CHOICES = (
    ('pr', 'pre-check'),
    ('su', 'success'), 
    ('fl', 'failed'),
  )

  address = models.TextField()
  ...
  geocode = models.TextField()
  geocode_status = models.CharField(max_length=2, 
                                    choices=GEOCODE_STATUS_CHOICES, 
                                    default='pr')

class AppUser(models.Model):
  name = models.CharField(max_length=100)
  ...
  address = models.ForeignKey(Address)

<强> app.tasks.py

  from celery import task
  from app.models import Address, AppUser
  from some_module import geocode_function #assuming this returns a string

  @task()
  def get_geocode(appuser_pk):
    user = AppUser.objects.get(pk=appuser_pk)
    address = user.address

    try:
      result = geocode_function(address.address)
      address.geocode = result
      address.geocode_status = 'su' #set address object as successful
      address.save()
      return address.geocode  #this is optional -- your task doesn't have to return anything
                                 on the other hand, you could also choose to decouple the geo-
                                 code function from the database update for the object instance.   
                                 Also, if you're thinking about chaining tasks together, you             
                                 might think about if it's advantageous to pass a parameter as 
                                 an input or partial input into the child task.

      except Exception as e:     
        address.geocode_status = 'fl' #address object fails
        address.save()
        #do something_else()
        raise  #re-raise the error, in case you want to trigger retries, etc

<强> app.views.py

from app.tasks import *
from app.models import *
from django.shortcuts import get_object_or_404

    def geocode_for_address(request, app_user_pk):
      app_user = get_object_or_404(AppUser, pk=app_user_pk)

     ...etc.etc.  --- **somewhere calling your tasks with appropriate args/kwargs

我相信这符合您上面列出的最低要求。我故意将视图保持未开发状态,因为我不知道你想要触发它的确切程度。听起来,当他们的地址无法进行地理编码时,您也可能需要某种用户通知(“我想更新数据库中允许用户知道的字段”)。如果不了解更多有关此要求的具体内容,我会听起来像是在您的html模板中最好完成的事情(如果instance.attribute值为X,在模板中显示q)或使用django.signals(设置为当user.address.geocode_status切换到失败时发出信号 - 例如,通过电子邮件通知用户让他们知道等等。)

在上面代码的注释中,我提到了将上面的get_geocode任务的组件部分解耦和链接的可能性。您还可以考虑通过编写自定义错误处理程序任务并使用link_error parameter(例如。,add.apply_async((2,2),link_error = error_handler.s)将异常处理与get_geocode任务分离。 (),其中 error_handler 已被定义为app.tasks.py中的任务。)此外,无论您选择通过主任务(get_geocode)还是通过链接错误处理程序处理错误,我都会认为你想要更具体地了解如何处理不同类型的错误(例如,做一些连接错误与地址数据格式不正确有关的事情。)

我怀疑有更好的方法,我刚刚开始理解你可以通过链接任务,使用组和和等来获得多么有创造力。希望这有助于至少让你思考一些可能性。我会留给其他人推荐最佳实践。