TL;DR / Key Takeaways
ネイティブタスクの20年待機が終わりました
約20年間、Django開発者たちは一つの明白な欠点を回避してきました。それは、バックグラウンド作業を実行するためのネイティブな方法がないことです。メールの送信、アップロードの処理、レポートの集計、またはサードパーティAPIの呼び出しはすべてサードパーティツールに依存しており、Celery は2000年代後半には事実上の標準となりました。
その非公式なスタンダードには代償が伴いました。チームは、単一のHTTPリクエストをブロックしないために、別のブローカー、ワーカープール、そして監視スタックを追加しなければならず、「歓迎のメールを送信する」や「カウンターを再計算する」といった些細なジョブでも同様でした。
コミュニティは、チケット、ブログ記事、カンファレンスでの講演を通じてこのギャップについて10年以上不満を訴えてきました。人々が実際に求めていたのは、すべてのプロジェクトにRedis、RabbitMQ、または特定のワーカー実装を強制しない、標準化されたビルトインの非同期作業用APIというシンプルなものでした。
その代わりに、エコシステムは分断されました。あるチームはCeleryに全てを賭け、他のチームはHuey、RQ、または独自のキューを選びました。ライブラリを入れ替えることは、侵襲的な書き換えを伴いました。なぜなら、各ライブラリは独自のデコレーター、結果オブジェクト、そしてアプリケーションコードに直接組み込まれた再試行セマンティクスを持っていたからです。
その圧力は最終的に、コア貢献者のジェイク・ハワードによる正式なDjango Enhancement Proposal(DEP)として結晶化しました。彼の提案したDjango Tasks DEPは、コアに存在し、公共APIを定義し、バックエンドが実装の詳細で競い合うことを可能にする最小限のプラグイン可能なDjango Tasks Frameworkを提案しました。
ハワードのデザインは明確な境界を示しました:Djangoは、タスクの宣言とキューへの追加方法を管理し、サードパーティのバックエンドはストレージ、ワーカー、スケーリングを担当します。この分割は、Djangoがデータベースやキャッシュを扱う方法と似ており、ビジネスロジックを単一のキューライブラリに結びつけることに疲れていたメンテナーたちにすぐに共鳴しました。
Django 6.0は、2025年12月に正式リリースされ、9月にアルファ、10月にベータ、11月にRC1がリリースされました。この提案が実際に実現した場所です。新しいタスクモジュールはフレームワークの一部として提供され、アドオンとしてではなく、すべての新しいプロジェクトは初日から一流のバッチ処理のストーリーを持っています。
この点で、Djangoの非同期ビューやマイグレーションフレームワークのスケールにおいて、建築的な転換点が示されました。バックグラウンド処理はもはや「後から結びつける外部システム」ではなく、他の機能やサードパーティ製アプリ、今後のDEPが直接構築できるコア機能となりました。
ジャンゴの新しい武器:プラガブルAPIレイヤー
Django 6.0の新しいDjangoタスクフレームワークは、定義と実行の間に明確な境界を設けています。コアDjangoは、タスクをどのように宣言し、キューにプッシュするかを標準化しましたが、キューを実行するもの、ワーカーの見た目、ジョブの保存場所については指示を出すことを拒否しています。その分離により、タスクはORMやリクエストスタックに組み込まれた単一のバックグラウンドワーカーではなく、プラグイン可能なAPIレイヤーへと変わります。
システムの中心には、@taskデコレーターがあります。これを通常の関数に付けると、Djangoはそれをタスクとして登録し、キュー名、優先度、タスクコンテキストが必要かどうかといったメタデータを付加します。タスクはモジュールスコープ内に存在し、JSONシリアライズ可能な引数を取り、値を返さなければならず、`takes_context=True`を選択することで、試行回数や`TaskResult` IDを公開するコンテキストオブジェクトを受け取ることができます。
機能がタスクになると、`enqueue()`を使ってフレームワークに作業を委ねます。同期コードからは`enqueue(my_task, *args, **kwargs)`を呼び出しますが、非同期コードからはバックエンドが同じAPIのために`aenqueue()`を提供することができますが、これはawaitされます。内部では、Djangoはこの呼び出しを設定されたバックエンドに渡し、バックエンドはそれがRedisにメッセージをプッシュすることを意味するのか、Postgresに書き込むことを意味するのか、あるいは全くカスタムの処理を行うのかを決定します。
すべての `enqueue()` の呼び出しは、Django における「私のジョブに何が起こったのか」という単一の抽象を表す TaskResult オブジェクトを返します。このオブジェクトには、データベースに保存したりクライアントに戻したりできるユニークな ID が含まれており、後で `get_result(id)` のようなもので再読み込みして、ステータス、エラーの詳細、試行回数、戻り値などのフィールドを調査することができます。フレームワークの利用者はバックエンドの内部に直接触れることはなく、TaskResult に対話し、バックエンドがそれを独自のストレージにマッピングすることを許可します。
意図的な不完全性がこのデザインを特徴づけています。Djangoは、本番用ワーカー、リトライエンジン、cronスタイルのスケジューラー、チェイニングAPIを提供しません。これらはすべてバックエンドやサードパーティライブラリに属します。コアは、`@task`、`enqueue()`、および`TaskResult`が安定していることを約束するだけで、エコシステムがこれを基にワーカーやダッシュボード、Celery、RQ、またはRedisへのブリッジを構築できるようにしています。
初期のバックエンドは意図的に最小限に留められています。`immediate` バックエンドは `enqueue()` を呼び出すとすぐにタスクを同期的に実行するため、スタックトレースやブレークポイントが通常の関数呼び出しと同じように動作するため、ユニットテストやローカルデバッグが極めて容易になります。`dummy` バックエンドは、何も実行せずにすべてのタスクを破棄するため、タスク呼び出しをそのまま保持する必要があるが、実際の実行を許可できない特定のステージングやドライラン設定などの環境に最適です。
あなたが待ち望んでいた「80%の解決策」
Djangoにおけるバックグラウンドワークは、主に同じ3つの作業を繰り返すことを意味しています。電子メールの送信、ユーザーアップロードの処理、外部APIとのやり取りです。その「80%のユースケース」では、ファンアウトワークフロー、分散ルーティング、またはキューごとのレート制限はほとんど必要ありません。ただ、SMTPサーバー、S3バケット、または決済プロバイダーが起動するまでリクエストスレッドをブロックしないようにするだけで済みます。
Django Tasks Frameworkは、直接そのバンドをターゲットにしています。関数に@taskを装飾し、`enqueue()`(または`aenqueue()`)を呼び出すことで、「このパスワードリセットメールを送信する」や「この画像のサムネイルを生成する」といった作業を引き渡します。多くのアプリにとって、この単一のパターンは、パスワードリセット、オンボーディングシーケンス、ウェブフックの送信、PDF生成、キャッシュウォーマーをカバーしています。
歴史的に、チームはそのような作業のためにCeleryを使用し、少数の関数のためにフルキューのスタックを運用することになりました。ブローカー、結果のバックエンド、ワーカープール、ビートスケジューリング、そして最初のメールが送信される前に設定の森が必要でした。Django Tasks Frameworkは、APIを標準化することで、単純なケースにおいてその要件を排除し、背後にある重い機械については中立的な立場を保っています。
それをエントリランプのように考えてください:RabbitMQ、Redis、またはKubernetes規模のワーカー・ファームにコミットするずっと前に、タスクを宣言しキューに追加するための一つの方法にコミットします。初期段階のプロジェクトは即時バックエンドから始め、その後トラフィックとレイテンシの要求に応じて実際のキューを使用したワーカーに置き換えることができます。大規模なリファクタリングは不要で、コードベース全体にわたってCelery特有のデコレーターを取り除く必要もありません。
Djangoの独自バックエンドは意図的に最小限に抑えられています:インラインで作業を実行する即時バックエンドと、実行されないダミーバックエンドがそれです。これにより依存関係が少なくなり、すべてがDjangoネイティブの感触を保持し、CRUDアプリや内部ツールのために余分なデーモンを引き込むことを避けています。バックエンド、コンテキスト、および結果の処理に関する詳細は、Django 6.0 タスクフレームワークドキュメントで、サードパーティのワーカーが接続する契約が明記されています。
現代のDjangoタスクの構造
Django 6.0のバックグラウンド作業は、新しい@taskデコレーターでラップされた単純なPython関数から始まります。最小限の例は次のようになります:
```python from django.tasks import task, enqueue, aenqueue, get_result ```
@task( priority=5, queue_name="notifications", takes_context=True, ) def notify_user(task_context, user_id, message): """ ユーザーに通知を送信します。
タスクコンテキスト: takes_context=Trueの場合に挿入される ユーザーID: ユーザーのデータベースID メッセージ: 通知のテキスト本文 """ # この特定の実行試行に関するメタデータにアクセス = task_context.attempt # 初回は1、リトライ時に増加 result_id = task_context.task_result_id # 追跡用の安定したID
# 実際のロジックはここに入ります(メール、プッシュ、SMSなど) # 観測可能性のために attempt/result_id をログに記録できます return {"status": "sent", "attempt": attempt, "result_id": result_id}
これらのデコレータ引数は、Djangoが公開するコアの設定項目です。priorityはバックエンドへの数値的ヒントであり、高い数値は「同じキュー内の他のジョブに対して早く実行する」という意味です。queue_nameは、作業を「notifications」や「image-processing」のような特定のキューにルーティングします。一方、`takes_context=True`は、最初のパラメータとしてtask_contextオブジェクトを注入します。
task_contextは、忘れ去られるような関数を実際に観察できるものに変えます。`task_context.attempt`は、このタスクがこれまでに何回実行されたかを示し、バックエンドが再試行を追加する際には重要になります。`task_context.task_result_id`は、データベース、ログ、または分析に保存できる安定した識別子を提供し、後でこの実行に再接続できるようにします。
作業をキューに入れる際には、同期コード用の enqueue() ヘルパーを使用します。ビューまたはシグナルハンドラーからは、次のように行うことができます:
```python def create_order(request): # ... 注文を作成し、トランザクションをコミット ... result = enqueue( notify_user, user_id=request.user.id, message="ご注文が発送されました!", ) # result.id == task_result_id return JsonResponse({"task_id": result.id}) ```
非同期コードでは`aenqueue()`を使用し、Djangoの非同期ビューやコンシューマと同様にします。
```python async def async_view(request): result = await aenqueue(notify_user, user_id=1, message="こんにちは") return JsonResponse({"task_id": result.id}) ```
`task_result_id`を取得したら、ステータスチェックが`get_result()`を介して実行されます:
```python from django.http import JsonResponse from django.views.decorators.http import require_GET ```
```python @require_GET def task_status(request, task_id): result = get_result(task_id) return JsonResponse( { "id": result.id, "status": result.status, # 例: "pending", "running", "finished", "failed" "attempts": result.attempts, # これまでの総試行回数 "value": result.value, # notify_userからの返戻値、完了時 "error": result.error, # 失敗時のバックエンド特有のエラー情報 }) ```
そのトリオ — `@task`、`enqueue()`/`aenqueue()`、および `get_result()` — は、すべてのDjangoタスクフレームワークバックエンドが尊重しなければならない最小限の標準化されたインターフェースを形成します。
欠けたピース: ジャンゴが省略するもの
驚きの展開はありません:Django 6.0はビルトインのワーカーを搭載していません。Djangoタスクフレームワークを使ってタスクを定義し、キューに入れることはできますが、プロダクション環境では、バックエンドからジョブを取得して実行するために別の長時間実行プロセスが必要です。公式ドキュメントや初期の講演でも強調されていますが、開発シェルを離れると「Djangoタスクワーカー」やそれに相当するものが必須になります。
DjangoのコアAPIは、Celeryユーザーが当然のように享受する便利さも省略しています。メールプロバイダーがタイムアウトした際の自動再試行のための公式サポートはなく、組み込みのcronスタイルのスケジュールもありませんし、ネイティブなタスクチェーンやグループも存在しません。「これを5分ごとに実行する」や「AとBが成功した後にタスクCをのみ開始する」といったロジックは、django.tasks には見当たりません。
これらの機能は、接続するバックエンドによって完全に実装されます。Redisをバックエンドとしたワーカー、RQブリッジ、または将来のCeleryアダプターが、リトライ、バックオフ戦略、定期ジョブ、ファンアウト/ファンインパイプラインの実装方法を決定します。Djangoは、安定したインターフェースである`@task`、エンキュー呼び出し、バックエンドが拡張できるTaskResult抽象化を提供するだけです。
Django Tasks Frameworkのデザイナーは、最初の段階からこの制約を明示しました。Core Djangoには即時バックエンド(タスクをインラインで実行)とダミーバックエンド(決して実行しない)のみが搭載されており、両方とも意図的にプロダクション環境を想定していません。実際にジョブを保持したり、ワーカーを調整したり、分散実行を管理したりするものは、サードパーティパッケージから提供されます。
その分割は責任の明確な境界を生み出します。Djangoはインターフェースを所有します:タスクの宣言方法、引数の渡し方、結果の検査方法です。コミュニティは実装を所有します:タスクがどのようにシリアライズされるか、キューにどのように入るか、ワーカーがどのようにコンテナや地域にまたがってスケールするかです。
Celeryに慣れたチームにとって、これはほぼ素の状態のように感じられます。標準化された、フレームワークに祝福されたエントリーポイントを得る一方で、選択したバックエンドが再度導入するまで、バッテリー完備のスケジューラ、インスペクタ、リトライオーケストレーションを失います。初期の実験では、Redis、RQ、さらにはCelery自体をターゲットにし、DjangoタスクフレームワークAPIと連携するバックエンドとして利用しています。
長期的には、これはDjangoの既存のパターンを反映しています:ORM、キャッシュ、およびメールレイヤーが契約を定義し、Postgres、Redis、およびSMTPサーバーが重い作業を実行します。タスクは意図的に未完成のまま、そのリストに追加されました。
セロリ王国が襲撃されている?
Celeryは、一つの約束のもとにその王国を築きました:Djangoが気にするずっと前からの工業レベルのバックグラウンドジョブです。今、Django 6.0はタスク宣言をコアに組み込んだDjangoタスクフレームワークを搭載し、突然、Celeryはもはやデフォルトの前提ではなく、ボード上の最大のプレーヤーとなりました。
並べて見ると、モデルは非常に異なります。Django Tasksは標準APIを定義しています:`@task`、エンキュー関数、および`TaskResult`オブジェクトを使用し、ストレージと実行はプラグ可能なバックエンドに委任しています。Celeryは完全なスタックを提供します:ブローカー、ワーカー、スケジューラー、結果ストア、そして10年のエコシステムツールが含まれています。
簡単な比較をすれば、その違いは明らかです:
- 1Djangoタスク:Djangoの一部、最小限の設定、JSONのみのペイロード、リアルキューに必要なバックエンド
- 2セロリ:別パッケージ、RedisやRabbitMQのようなブローカーが必要、複雑なシリアライゼーションをサポート、ワーカーとビートスケジューラーを含む
- 3Djangoタスク:メール、アップロード、API呼び出し、コミット時フックに最適
- 4セロリ:分散クラスター、高スループット、およびマルチサービスアーキテクチャ向けに調整されています
セロリは依然としてスケールと複雑さが重要な場面で支配的です。指数バックオフを伴う組み込みのリトライ、ビートを介した定期的なタスク、チェーン、グループ、コードのようなワークフロープリミティブにより、複数のワーカーにわたる多数のジョブを調整します。大規模なデプロイメントでは、RedisやRabbitMQをバックエンドに使用して、毎秒数千のタスクをセロリを通じて提供することが一般的です。
Django Tasksは、代わりにエルゴノミクスに重点を置いています。Django内に留まり、`django.tasks`からインポートし、関数をデコレートして、ブローカーに直接触れることなく`enqueue()`を呼び出します。およそ「80%のユースケース」— トランザクションメール、サムネイル生成、キャッシュウォーマー、Webhookのファンアウト — において、Django内でのゼロ依存の感覚は、主要な導入障壁を取り除きます。
パワーユーザーは、今日Celeryを手放すといくつかの利点を失います。公式のワーカーはなく、ネイティブの再試行ポリシーもなく、組み込みのスケジューリングもなく、戦闘実績のある監視UIもDjango 6.0には含まれていません。これらの要素はコミュニティのバックエンドとサードパーティのダッシュボードに存在しますが、依然としてCeleryの成熟したエコシステムには及びません。
戦略的に、Django Tasksはチームが尋ねるデフォルトの問いを変えます。新しいプロジェクトはコアフレームワークから始まり、要件が明確に分散ワークフロー、先進的なルーティング、または厳格なSLAを必要とする場合にのみCeleryを使用します。Celeryはエスカレーションの道となり、出発点ではなくなります。
では、Django 6.0はCeleryを殺すのでしょうか?いいえ — Celeryの領域を狭めるだけです。バックグラウンドジョブはデフォルトでDjangoに属し、一方でCeleryは高性能でマルチノードの「ジョブを決して落とさない」最前線を守っています。より深い技術的詳細については、Django 6.0 リリースノートで新しいDjangoタスクフレームワークが実際のバックエンドにどのように統合されるかが詳述されています。
どうしてもセロリが必要なとき
セロリは、バックグラウンド作業がサイドクエストのように見えなくなり、自身の分散システムのように見え始めるとき、いつでも勝ちます。数百のワーカー、地域に分散された複数のキュー、1秒あたり10,000件以上のジョブの急増時における予測可能な動作が必要なとき、Celeryの10年以上の戦歴は、Djangoの新しい輝きよりも重要です。
高度なルーティングロジックが必要な場合は、「ファイア・アンド・フォゲット」ではなくCeleryを使用してください。つまり、以下のような機能があります: - サービスごとの複数のキューと詳細なルーティングキー - タスクごとのレートリミティングと同時実行制限 - 厳密および柔軟な時間制限、そして自動サーキットブレーカー動作
真剣なワークフローは、依然としてCeleryのAMQPサポートとブローカーの柔軟性に依存しています。もしあなたのアーキテクチャが既にRabbitMQ、Redis、あるいはその他のエキゾチックなブローカー上で稼働しているなら、耐久性のあるキュー、メッセージの確認、デッドレターエクスチェンジ、そしてDjango Tasks Frameworkが意図的に定義していないバックプレッシャーセマンティクスを手に入れることができます。
複雑なパイプラインは、再びCeleryに戻ることになります。コルド、グループ、チェーン、キャンバスを使うことで、ファンアウト/ファンインジョブや、複数ステップのETLパイプライン、数十のタスクやマシンにまたがる長時間のデータサイエンスワークロードをオーケストレーションできます。DjangoのタスクAPIは作業をキューに追加できますが、そのようなワークフローグラフをモデル化しているわけではありません。
モニタリングは別の境界線です。Flower、Prometheusダッシュボード、Celeryのイベントストリームに基づいて構築されたカスタムGrafanaボードの内部で活動するチームは、「TaskResultを確認する」という代替案を受け入れません。Celeryは、SREがSLAを維持するために使用するワーカーごとのメトリクス、キューの深さ、再試行の嵐、タスクのレイテンシヒストグラムを公開します。
高ボリュームのSaaSプラットフォーム、フィンテックのバックエンド、そして1日に数百万件のジョブを処理するマーケットプレイスは、依然としてCeleryをコアインフラとして扱っています。そのような層において、Celeryの実績のある再試行のセマンティクス、結果バックエンド、そして運用ツールは、Djangoの若いプラグイン可能な層には匹敵するものがありません。
エコシステムが目覚める
Django Tasks Frameworkが統合されるやいなや、Djangoの世界に衝撃が走りました。6.0リリース候補の数日後、コミュニティのリポジトリには「実験的な」Redisバックエンド、タスクランナー、管理インテグレーションが次々と登場し、シンプルなAPIを実際に本番環境に展開できるものへと進化させようとしています。
初期の採用者たちは明らかなギャップに目を付けました。それは、新しいインターフェースを話す、実稼働可能なワーカーです。Redisのリストやストリームをラップし、`worker`管理コマンドを起動し、`@task`から`priority`および`queue_name`をRedisデータ構造に直接マッピングするパッケージが登場し、実質的にDjango Tasks Frameworkの背後に軽量のRQスタイルのランナーを再現しました。
Redisはすぐにデフォルトのプレイグラウンドとなりました。一つのアダプターファミリーは、シンプルな設定に焦点を当てています—単一のRedisインスタンス、FIFOキュー、シャーディングなし—メール、画像処理、ウェブフック呼び出しの「80%ユースケース」に最適化されています。もう一つの波は、遅延ジョブ、バックオフベースの再試行、キューごとのレート制限など、より高度な機能を試験しています。これらはすべて、プレーンなデコレータのキーワード引数を通じて公開されています。
ブリッジパッケージは、既存のエコシステムを置き換えるのではなく、接続することを目指しています。すでに、CeleryスタイルのブローカーURLを再利用し、すべてのタスク定義を`@task`を通じてルーティングするプロトタイプが見つかります。これにより、あなたのコードはネイティブに見えますが、インフラストラクチャは依然としてCeleryの強化されたワーカーと監視ツールに依存しています。
最も野心的なものは、Celeryが標準のDjangoタスクAPIの背後でドロップインワーカーとして機能する「Celeryバックエンド」の初期スケッチです。このアイデアは、タスクがフレームワークにネイティブである一方で、バックエンドアダプターが`enqueue()`呼び出しをCeleryタスクに変換し、結果IDをマッピングし、ステータスチェックをプロキシすることで、数年間のタスクコードを再記述することなく段階的に移行できるというものです。
Djangoのメーリングリスト、GitHubの問題、Twitterのスレッドでの議論は、観測性、ライフサイクルフック、洗練された管理者UXの3つの欠けている柱に集中しています。人々は「タスク開始 / 再試行 / 失敗」のための構造化されたイベント、Better Stackなどのツールにこれらのイベントをストリーミングできるプラグイン可能な監視バックエンド、そしてDjangoの管理者内でキュー、ワーカー、ホットパスを直接表示するファーストクラスのダッシュボードを求めています。
もしこのパターンが続くなら、今後6〜12ヶ月の間にダーウィン式のエコシステムを期待してください。半ダースのRedisワーカー、少なくとも1つのCeleryブリッジ、そして「バッテリー付き」の配布版がいくつか、Django 6.0タスクの事実上の標準バックエンドを目指して戦うことになるでしょう。
実務上の障害と注意点
JSONが最初です。Djangoのタスクは、引数と戻り値をJSONを使用してシリアライズします。つまり、タスクに渡すものはすべてJSON互換でなければなりません:文字列、数値、ブーリアン、リスト、辞書。`datetime`、`Decimal`、またはモデルインスタンスを渡すと、シリアライズエラーが発生したり、バックエンドが厳格な型を強制し始めると静かなデータの損失が生じます。
これを回避することはできますが、明示的である必要があります。複雑なオブジェクトをプimitivesな表現(ID、ISO 8601文字列、単純な辞書)に変換し、タスク内で再構築してください。良いルールとしては、`json.dumps()` / `json.loads()` のラウンドトリップを生き延びられないものであれば、タスクの引数や戻り値として送信しないことです。
データベースへの書き込みは、もう一つの鋭い問題を引き起こします。`transaction.atomic()`内で実行されるビュー中にタスクをキューに追加すると、そのタスクはトランザクションがコミットされる前に実行され、古いデータを参照したり、欠落した行で失敗する可能性があります。Djangoのon_commitフックは、まさにその競合を回避するために存在します。
記憶のためのパターン:書き込みを行った後、`on_commit`からタスクをスケジュールします。例えば、`Order`を作成した後に、`transaction.on_commit(lambda: send_order_email.enqueue(order_id=order.id))`を使用することで、ワーカーはコミットされた状態のみを認識します。これをスキップすると、負荷がかかるときや遅いデータベースでのみ現れるハイゼンバグが発生します。
ワーカーはまだあなたのメインプロセスの外で動いています。systemd、Supervisor、またはKubernetes Jobsのようなものの下で、専用のワーカープロセス(またはいくつか)を実行する必要があります。つまり、Celeryに対してすでに行っているのと同様に、追加のデプロイメントマニフェスト、ヘルスチェック、ロギング、再起動ポリシーが必要になります。
運用面では、この新しいスタックは依存関係を縮小しますが、責任は減りません。依然として同時実行制限、キューのバックプレッシャー、そしてプロセスが停止する前にタスクが完了できるようにするための優雅なシャットダウンについて考慮する必要があります。多くのチームにとって、それは新しい運用のレイヤーであり、無料の機能ではありません。
「組み立てが必要な」カテゴリーの土地を監視しています。CeleryはFlower、Prometheusエクスポーター、そして何年にもわたるダッシュボードを備えていますが、Django Tasksにはそれがありません。初期のバックエンドは`TaskResult`を通じて基本的なステータスを公開しますが、おそらくカスタム管理ビュー、ログ、またはAPM統合を最初に接続するでしょう。
ソースレベルの探索が役立ちます。Djangoタスクフレームワークのソースコードは、結果、ステータス、エラーの流れを正確に示しており、より充実したサードパーティ製UIやメトリクスが追いつくのを待つ間、これを頼りにすることができます。
Djangoタスクでの次のステップ
既存のDjangoプロジェクトは、Djangoタスクフレームワークを段階的なアップグレードとして扱うべきであり、一挙に移行するものではありません。すでに本番環境でCelery、RQ、またはHueyを運用しており、正常に動作している場合は、重要なパスではそれらを保持し、新しい低リスクのフローに対してのみDjangoタスクを導入してください。新しいAPIのv1において、複雑なCelery構成を全面的に書き直すことはほとんど効果がありません。
Django 6.0で始まる新しいプロジェクトでは、「80%」の作業(メール送信、サムネイル生成、キャッシュウォーマー、シンプルなサードパーティAPI呼び出し)には安全にDjango Tasksをデフォルトとして使用できます。複数のキューにわたる数千のタスクや、大規模なスケジュールされたジョブ、サービス間のワークフローが必要な場合にのみCeleryを検討してください。
Django 5 に留まっているチームは、公式の バックポート を利用して今日から試すことができます。バックポートパッケージをインストールし、それを `INSTALLED_APPS` に追加し、即時またはダミーバックエンドを設定することで、初日に Redis や RabbitMQ を立ち上げる必要がなくなります。Django 6.0 と同じ `@task` デコレーターと `enqueue()` API を、フレームワーク全体のアップグレードなしで利用できます。
安全な実験とは、重要でない機能を選び、その機能をフィーチャーフラグの背後でDjangoタスクに置き換えることを意味します。理想的な候補には以下が含まれます:
- 1パスワードリセットまたはサインアップ確認メール
- 2「登録ありがとうございます」または「ご注文を受け付けました」通知
- 3低ボリュームのウェブフックを分析またはログサービスに送信
ユーザーモデルが保存された後にキューイングするために `on_commit()` を使った単一のパスワードリセットメールをバックグラウンドタスクに移動することから始めます。開発環境では即時バックエンドを使用し、ステージングではシンプルなRedisバックエンドと単一のワーカープロセスに切り替えます。収益に関連するものに手を加える前に、リクエストのレイテンシとタスクの失敗率を測定してください。
JSONのみのシリアライゼーションを制約ではなく強制的な機能と見なしてください:タスクの引数をフルモデルインスタンスではなく、IDやプリミティブにリファクタリングしてください。この規律により、Celery、Redisバックエンド、または将来のDjangoタスクフレームワークアダプターとの切り替えが容易になります。
戦略的に、Django TasksはDjangoのバッテリーを内蔵したウェブフレームワークとしての成熟点を示しています。バックグラウンド作業は共通のコアAPIを使用するため、依存関係の膨張が抑えられ、大多数のウェブアプリケーション(産業グレードのCeleryオーケストレーションを必要としないもの)に対して、Djangoはより競争力があり、自己完結型となっています。
よくある質問
新しいDjangoタスクフレームワークとは何ですか?
Django 6.0には、バックグラウンドタスクを定義およびキューイングするための組み込みAPIがあります。タスクの作成方法を標準化しますが、実行には別途バックエンドおよびワーカープロセスが必要です。
Django 6.0はCeleryを完全に置き換えますか?
いいえ。このフレームワークは、電子メールの送信などのよりシンプルで一般的なユースケース(「80%の解決策」)のために設計されています。組み込みの再試行やチェーンを持つ複雑で分散されたワークフローには、Celeryがより強力なツールとして残ります。
Djangoタスクフレームワークにはワーカーが含まれていますか?
いいえ、そうではありません。これはDjangoのコアをスリムに保つための設計です。サードパーティのバックエンドを設定し、タスクを実行するために別のワーカープロセスを実行する必要があります。
新しいタスクAPIは、古いDjangoバージョンで使用できますか?
はい、バックポートライブラリを使用すると、Django 5で新しいタスクAPIを利用できるようになり、Django 6.0への移行のための実験や準備が容易になります。