Celeryは、時間のかかるタスクをバックグラウンドワーカーに委譲することで、メインアプリケーションの応答性を維持できます。しかし、task.delay()を呼び出してもタスクが実行されない場合は、いくつかの設定の問題やミスが原因である可能性があります。

この記事では、これらの問題を調査し、タスクをスムーズに実行するための解決策を示します。

考えられる原因と解決策

1. Celeryワーカープロセスが実行されていない

Celeryのタスクはワーカーによって処理されるため、ワーカーが実行されていないと、タスクは処理されません。

celery -A proj worker --loglevel=INFO


上記の命令を実行して、ワーカーが実行されていることを確認してください。projはCeleryアプリケーションの名前に置き換えてください。デフォルトでは、celeryワーカープロセスはDEFAULTキューを監視します。そのため、タスクキューを別のもの(例:QuickBooks、Stripe)としてマークする場合は、ここでキュー名を指定する必要があります。

celery -A proj worker --loglevel=INFO -Q default,quickbooks,stripe
解決策:

task.delay()を呼び出す際には、常に少なくとも1つのワーカーが実行されていることを確認してください。

2. Celeryブローカーの設定が正しくない

Celeryは、RabbitMQやRedisなどのメッセージブローカーを使用してタスクをキューイングします。ブローカーの設定が正しくない場合、またはブローカーが実行されていない場合、タスクはキューに送信されません。

  settings.pyの例: CELERY_BROKER_URL = 'redis://localhost:6379/0'
# Rabbitmq: amqp://myuser:mypassword@localhost:5672/myvhost


ブローカーのURLが正しく、ブローカーサービスが稼働していることを確認してください。

解決策:

設定ファイルのCELERY_BROKER_URLを再確認し、ブローカー(例:RedisまたはRabbitMQ)が動作していることを確認してください。

3. タスクが登録されていない

タスクがCeleryアプリケーションに登録されていない場合、task.delay()を呼び出しても何も起こりません。これは、タスクがインポートされていないか、正しくデコレートされていない場合によく発生します。

例:
from celery import Celery
app = Celery('proj')

@app.task
def add(x, y):
    return x + y


タスクが@app.taskで適切にデコレートされ、必要な場所で正しくインポートされていることを確認してください。

  解決策:

タスクがCeleryアプリケーション内で適切に定義され、登録され、インポートされていることを確認してください。

4. タスクキューの設定ミス

Celeryでは、タスクを特定のキューにルーティングできます。ワーカーが正しいキューを監視していない場合、タスクは実行されません。

  settings.pyの例:
CELERY_TASK_ROUTES = {
    'proj.add':
    {
        'queue': 'math_tasks'
    },
}


ワーカーが正しいキューを監視するように設定されていることを確認してください。

celery -A proj worker -Q math_tasks --loglevel=INFO

解決策:

タスクが既存のキューにルーティングされており、ワーカーがそのキューからのタスクを処理するように設定されていることを確認してください。

5. データベース接続の問題

タスクがデータベースとやり取りし、接続に問題がある場合(例:データベースがダウンしている場合)、タスクはトリガーされずにサイレントに失敗する可能性があります。

  タスクの例:
@app.task
def save_to_db(data):
    # データベース操作はこちら
    pass

解決策:

データベース接続がアクティブであり、データベース操作を含むCeleryタスクを実行する前に必要なマイグレーションが適用されていることを確認してください。

6. イーガーモード

Celeryには、「イーガーモード」があり、タスクはワーカーに送信される代わりにローカルで実行されます。このモードはテストに役立ちますが、タスクがキューイングされることを期待している場合に混乱を招く可能性があります。

  settings.pyの例:
CELERY_TASK_ALWAYS_EAGER = False


タスクをキューイングするには、設定でCELERY_TASK_ALWAYS_EAGERをFalseに設定してください。

解決策:

意図しない限り、イーガーモードで実行していないことを確認してください。

7. タスクの有効期限

デフォルトでは、Celeryタスクには有効期限があります。この時間枠内にタスクが実行されない場合、破棄され、タスクがトリガーされなかったように見える場合があります。

有効期限付きタスクの例:
add.apply_async((10, 20), expires=60)

解決策:

必要に応じて有効期限を調整して、タスクが早期に破棄されないようにします。

8. ブローカーとワーカーのタイムゾーンの不一致

ブローカーとワーカー間のタイムゾーンに不一致があると、タスクが正しくスケジュールされず、タスクが遅延したり、まったく実行されなかったりする可能性があります。

  例:
CELERY_TIMEZONE = 'UTC'


ブローカーとCeleryワーカーの両方で同じタイムゾーン設定を使用していることを確認してください。この問題に関するgithubのリンクはこちらです

  解決策:

スケジューリングの問題を避けるために、ブローカーとCeleryワーカー間のタイムゾーンを同期させてください。

よくあるエラーとデバッグのヒント

問題を特定するための実用的なデバッグのヒントを次に示します。

  1. ログを有効にする:タスクで何が起こっているかを追跡するために、詳細なログを使用します。

    celery -A proj worker --loglevel=DEBUG
  2. タスクキューを検査する:Celeryのinspectコマンドを使用して、ワーカーとタスクの状態を確認します。

    celery -A proj inspect active
  3. ブローカーを確認する:ブローカーとしてRedisを使用している場合は、Redisに接続して次のコマンドを実行することで、保留中のタスクのリストを確認できます。

    redis-cli keys *

結論

task.delay()がCeleryタスクをトリガーしない場合は、通常、ワーカーが実行されていない、ブローカーの設定が間違っている、タスクの登録に問題があるなどの設定の問題が原因です。

これらの潜在的な問題点を体系的にチェックすることで、問題を迅速に特定して解決できるはずです。

高度なCeleryの設定についてはこちらをご覧ください。