2

Celery の結果とエラーに関する一般的な戦略をよりよく理解しようとしています。

結果にはステータス/状態があり、要求に応じて結果が保存されます。このデータはいつ使用しますか? エラー処理とデータ ストレージはタスク内に含める必要がありますか?

私の目的をよりよく理解するのに役立つ場合に備えて、サンプルシナリオを次に示します。

ユーザーの住所を goeocode するジオコーディング タスクがあります。タスクが失敗または成功した場合、データベース内のフィールドを更新してユーザーに知らせたいと思います。(エラー処理) 成功したら、ジオコーディングされたデータをデータベースに挿入したい (データ ストレージ)

どのようなアプローチを取るべきですか?

4

1 に答える 1

1

私はまだセロリの感触を自分自身で得ていると言って、これを前置きさせてください。そうは言っても、私はこれにどのように取り組むかについて一般的な傾向があり、他の誰も応答していないので、それを試してみます。

あなたが書いたものに基づいて、比較的単純な(私は最適化されていないと思いますが)解決策は、ドキュメントからのブログコメントスパムタスクの例の広い輪郭に従うことです。

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パラメーター(たとえば、add.apply_async((2、2)、link_error = error_handler.s()、ここで、error_handlerはapp.tasks.pyでタスクとして定義されています。また、メインタスク(get_geocode)を介してエラーを処理するか、リンクされたエラーハンドラーを介してエラーを処理するかを選択する場合は、もっと具体的にしたいと思います。さまざまな種類のエラーを処理する方法について(たとえば、アドレスデータが正しくフォーマットされていない場合とは異なる接続エラーで何かを行う)。

より良いアプローチがあるのではないかと思います。タスクを連鎖させたり、グループやコードを使用したりすることで、いかに独創性が得られるかを理解し始めたばかりです。これが少なくともいくつかの可能性について考えさせるのに役立つことを願っています。ベストプラクティスを推奨するのは他の人に任せます。

于 2012-12-27T23:21:28.857 に答える