让我先说我自己仍然对 Celery 有感觉。话虽如此,我对如何解决这个问题有一些普遍的看法,由于没有其他人回应,我会试一试。
根据您所写的内容,一个相对简单(尽管我怀疑未优化)的解决方案是遵循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 切换到失败时发出信号——例如,通过电子邮件通知用户等)。
在上面代码的 cmets 中,我提到了解耦和链接上面 get_geocode 任务的组件部分的可能性。您还可以考虑通过编写自定义错误处理程序任务并使用 link_error parameter(例如 add.apply_async((2, 2), link_error=error_handler.s())将异常处理与 get_geocode 任务分离,其中 error_handler 已被定义为 app.tasks.py 中的任务)。此外,无论您选择通过主任务(get_geocode)还是通过链接的错误处理程序来处理错误,我都认为您可能希望更具体地了解如何处理不同类型的错误(例如,对连接错误做一些不同于地址数据格式不正确的事情)。
我怀疑有更好的方法,而且我刚刚开始了解通过链接任务、使用组和和弦等可以获得的创造性。希望这至少可以帮助您思考一些可能性。我会留给其他人推荐最佳做法。