株式会社renue
AI導入・DXの悩みをプロに相談してみませんか?
AIやDXに関する悩みがありましたら、お気軽にrenueの無料相談をご利用ください。 renueのAI支援実績、コンサルティングの方針や進め方をご紹介します。
FastAPI + Celery + Azure運用は「定期タスクをどこで動かすか」の決断から始まる
FastAPIベースの本番バックエンドで非同期処理・バッチ処理を組む時、2026年の実務者が最初に悩むのは「Celery Beatで回すか、クラウドネイティブなジョブ基盤(Azure Container Apps Jobs、Google Cloud Run Jobs、AWS Batch等)で回すか」という選択です。両者は併用可能ですが、役割の切り分けを間違えると、スケジューラーの重複、監視の二重化、コスト分散、インシデント対応の混乱を招きます。
本記事では、FastAPI + Celery + Redis にクラウドのアプリ基盤とジョブ基盤を組み合わせた構成で整理した「役割分担設計」「SSL付きRedisの設定」「Celery Beat crontab運用」「テナント横断タスク自動検出」「Azure Container Apps Jobsのcron設計」「本番運用の10原則」を、匿名化して共有します。Django + Celeryのガイドとは異なり、FastAPI + SQLAlchemy + マルチテナント + Azure特有の落とし穴に焦点を当てた実装記事です。
関連記事としてマルチテナントFastAPIバックエンド設計ガイド、LLMOps実践ガイド、MCP完全ガイドも併せてご参照ください。
2つのスケジューラーをどう役割分担するか
Celery Beat(アプリケーション内スケジューラー)
Celery Beatは、Celeryと同じアプリケーションコードベース内でスケジュールを定義し、Redis等のブローカーを経由してCeleryワーカーに定期タスクを投入する方式です。メリットは、(1) コード変更と同じPRで追加・変更が完結、(2) アプリケーションのコンテキスト(モデル、設定、依存ライブラリ)をそのまま使える、(3) 既存のFastAPIアプリとの統合が自然、の3点です。
一方で、(1) Beat自体が単一障害点になりがち、(2) ワーカー再起動時にスケジュール遅延が起きる、(3) 大規模並列実行には向かない、という制約があります。
クラウドネイティブジョブ基盤(Azure Container Apps Jobs等)
Azure Container Apps Jobs、Google Cloud Run Jobs、AWS Batchなどのクラウドネイティブジョブ基盤は、アプリケーションとは独立したコンテナイメージで、スケジュールもクラウド側のcron設定で管理します。メリットは、(1) アプリケーションとジョブのライフサイクル分離、(2) 失敗時の自動リトライやDead Letter Queueが標準装備、(3) リソース割り当て(CPU/メモリ)をジョブごとに独立制御、(4) 監査ログがクラウドネイティブに残る、の4点です。
一方で、(1) 新規ジョブ追加時にアプリとインフラの両方を更新する必要がある、(2) テナント横断処理や複雑な依存関係のあるタスクはやや扱いづらい、(3) 小さなタスク(数秒で終わる処理)には起動オーバーヘッドが大きい、という制約があります。
実務での役割分担
両者を併用する前提で、次のように役割を分担するのが実務的です。
- Celery Beat(アプリ同居):FastAPIアプリケーションと密結合する「データ同期」「API非同期処理」「テナント横断で軽量な定期処理」「リアルタイム応答のトリガー起点となるタスク」。例:外部SaaSからのデータ同期、KPIの日次集計、レポートの定期取得など。
- Azure Container Apps Jobs:アプリとは独立させたい「重いバッチ」「長時間処理」「大量トランザクションを扱うETL」「定型オペレーションの自動化」「時間指定の配信処理」「外部ATS連携の同期処理」「月次・四半期集計」。
この分担の判断軸は「(1) FastAPIアプリのメインコンテナと共有したいコンテキストがあるか」「(2) 失敗時の独立リトライが必要か」「(3) リソース割当を独立させたいか」の3点です。
Celery Beat運用の実装パターン
Redis接続のSSL対応(Azure/AWS/GCP共通)
マネージドRedis(Azure Cache for Redis、AWS ElastiCache、GCP Memorystore等)は、クラスタ設定やセキュリティポリシーでSSL接続を要求するケースがあります。マネージドRedisでは環境変数の真偽値でSSLスキームを動的に切り替える実装が一般的です。
- SSL無効時:`redis://:{password}@{host}:{port}/{db}`(パスワードありの場合)または `redis://{host}:{port}/{db}`
- SSL有効時:`rediss://:{password}@{host}:{port}/{db}` を使用。`rediss://` プロトコルで接続します。証明書検証の設定は環境の要件に応じて選択してください。
ここで重要なのは、`ssl_cert_reqs` パラメータを省略するとCelery 5.x系では接続が失敗することです。これはCeleryの既知の挙動で、SSL接続時は明示指定が必要です。ローカル開発ではSSLを無効にし、本番環境でのみSSLを有効化する設定分離が推奨されます。
マルチテナントのタスク自動検出
マルチテナントSaaSでCeleryを使う場合、各テナントの `tasks.py` や `tasks/` ディレクトリを起動時に自動検出してincludeする仕組みが有用です。次のようなロジックが有効です。
- `tenants/` ディレクトリを走査し、各サブディレクトリ(テナントID)を取得
- そのテナントに `tasks.py` または `tasks/` があるか判定
- ある場合、`テナントのタスクモジュール` をCelery includeリストに自動追加
これにより、新規テナント追加時にはディレクトリを作ってタスクファイルを配置するだけでCeleryが自動検出します。Celeryアプリ側への手動配線追加は不要です。この仕組みは、大量のテナントを運用するSaaSにおいて、開発速度と運用ミス防止の両方に効きます。
Beat Schedule(crontab)の設計
Celery Beatのスケジュール定義には `celery.schedules.crontab` を使います。タイムゾーンは `app.conf.timezone = "Asia/Tokyo"` で明示指定することが重要です。これを忘れるとUTCで動作し、朝9:00(JST)のつもりが同日18:00(JST)にタスクが走る事故が起きます。
実務では、次のようなスケジュール定義パターンがよく使われます。
- 毎日決まった時刻:`crontab(hour=9, minute=0)` — 日次のデータ同期など
- 毎週決まった曜日:`crontab(hour=9, minute=0, day_of_week="mon")` — 週次の集計処理など
- 平日のみ:`crontab(hour=11, minute=0, day_of_week="mon-fri")` — 平日専用レポート系
- 10分ごと:`crontab(minute="*/10")` — 外部サービスのステータス巡回など
- 毎月1日:`crontab(hour=8, minute=30, day_of_month=1)` — 月次の集計処理など
スケジュール定義はPythonの辞書構造で管理するため、バージョン管理・レビュー・A/Bテストが容易です。一時停止したいジョブには `# NOTE: 一時停止中(YYYY-MM-DD)` のコメントを残し、理由と再開予定を明記する運用にすると、後から判断根拠を追えます。
Celeryタスクのログ記録(signal hook)
Celeryには `task_prerun`, `task_postrun`, `task_failure`, `task_retry` などのシグナルハンドラが用意されており、これらを使ってタスク実行ログをDBやObservabilityツールに記録できます。タスクごとに開始・終了時刻、ステータス、エラー内容、実行引数をDBに記録し、運用ダッシュボードで可視化する構成が有効です。
このロガーはCeleryアプリの初期化時に1行のimportで読み込ませることで、シグナルハンドラが自動登録される設計になっています。副作用import(side-effect import)のパターンですが、Celeryのシグナル登録では標準的な実装方法です。
Azure Container Apps Jobs運用の実装パターン
自動デプロイとTerraform同期
ジョブ基盤の構成をIaCで管理し、CIから自動デプロイする運用が有効です。既定ブランチへのマージで、変更検知・必要なイメージのみビルド・構成反映までを自動実行します。
この自動デプロイのトリガー対象は、ジョブ本体・インフラ定義・依存関係定義のパスに絞り込みます。無関係な変更ではジョブ再ビルドが発生しないよう、パスフィルタリングを厳密に設定するのが重要です。
ジョブごとの独立Dockerfile
Azure Container Apps Jobsは、ジョブごとに独立したDockerfileとイメージを持ちます。ジョブ単位にDockerfileを分ける構造で、各ジョブに必要な最小依存ライブラリだけをインストールする設計にしています。
この分離により、(1) ジョブ間の依存競合を回避、(2) イメージサイズを最小化、(3) 特定ジョブだけ別バージョンのライブラリを使いたい要件に柔軟対応、が可能になります。ただしjob数が増えるとDockerfileの重複が増えるため、共通ベースイメージを別途ビルドして継承する工夫が必要です。
ジョブ運用の規律
renueでは以下の運用ルールを厳守しています。
- `az containerapp job update` の直接実行は緊急時のみ:通常運用ではGitHub Actions経由のTerraform applyに統一。手動更新はdriftの原因になります。
- 緊急で直接更新した場合、必ずdriftを解消:同じ変更をインフラ定義とTerraform stateに反映します。
- Azure APIを読むジョブはManaged Identity必須:`DefaultAzureCredential` を使うジョブには Job Identity を `SystemAssigned` or `UserAssigned` に設定。
- 必要RBACを最小権限で付与:対象RGの`Reader`、Log Analytics Workspaceの`Log Analytics Reader` / `Monitoring Reader` 等、ジョブ別に必要最小限のロールを付与。
主要ジョブの種類
クラウドのジョブ基盤で運用されるジョブの代表例(機能分類のみ):
- 定型タスク管理:日次のタスク・課題自動管理
- 週次サマリー配信:週次メッセージの生成・配信
- 候補者同期(ATS連携):複数時間帯での候補者データ同期
- 求人同期(ATS連携):複数時間帯での求人データ同期
- オンボーディング:オンボーディング資料の定期配信
各ジョブはcron(UTC時間で設定)で時刻指定され、失敗時はAzure Container Apps側のリトライ機構で自動再実行されます。重要なジョブは別途Slack通知フックで成功/失敗を記録します。
Celery Beat vs Azure Container Apps Jobsの比較早見表
| 軸 | Celery Beat | Azure Container Apps Jobs |
|---|---|---|
| 起動オーバーヘッド | 小(ワーカー常駐) | 中〜大(コンテナ起動時間) |
| リソース分離 | 他タスクとワーカー共有 | ジョブごとに独立 |
| 失敗時のリトライ | Celeryの設定に依存 | クラウドネイティブで標準装備 |
| 監査ログ | 自前実装 | Azure Monitor等で標準収集 |
| 新規追加のしやすさ | コード変更のみ | コード + インフラ定義が必要 |
| 小さなタスク(数秒)の適性 | 適している | オーバーヘッド大 |
| 長時間処理・バッチ | ワーカー占有リスクあり | 適している |
| テナント横断処理 | アプリと同じコンテキストで容易 | 可能だがやや面倒 |
| アプリとのライフサイクル結合度 | 密結合 | 疎結合 |
| デプロイ方式 | アプリデプロイと同じ | Terraform + GitHub Actions等 |
renueの本番運用10原則
原則1:ジョブの性質でCelery BeatとAzure Jobsを使い分ける
「小さい・頻度高い・アプリと密結合」→ Celery Beat、「重い・頻度低い・独立リソース必要」→ Azure Container Apps Jobs、という線引きを最初に決めます。両方に散らばらせると監視と運用が二重化します。
原則2:Redis接続はSSL対応を環境変数で切替可能に設計する
環境変数の真偽値で `redis://` と `rediss://` を切り替える設計を初日から入れます。後付けは混乱の元です。
原則3:Celery Beatのタイムゾーンは `Asia/Tokyo` を明示する
デフォルトのUTCで動かすと、スケジュール定義と実運用時刻がズレて事故になります。`app.conf.timezone = "Asia/Tokyo"` を必ず設定します。
原則4:テナントタスクは自動検出の仕組みで新規追加を自動化する
自動検出の関数を用意し、テナント追加時にスケジューラ側の設定変更が不要になるようにします。
原則5:Celeryタスクのログはシグナルハンドラで統一記録
`task_prerun`, `task_postrun`, `task_failure`, `task_retry` をフックしてDBやObservabilityに統一記録します。各タスクに個別のログ処理を書くと漏れが出ます。
原則6:Azure Container Apps JobsはTerraform + GitHub Actionsで自動化
`az containerapp job update` の手動実行は緊急時のみとし、通常はmainブランチのPRマージで自動デプロイされる仕組みにします。手動運用が日常化するとdriftが必ず発生します。
原則7:Azure APIを叩くジョブはManaged Identity必須
API Keyや接続文字列を環境変数で渡すのは最終手段。Managed Identity + 最小権限RBACが標準です。
原則8:ジョブ別に最小依存のDockerfileを持つ
モノリシックな共通イメージではなく、ジョブごとにDockerfileを分離し、必要最小限の依存だけを含めます。イメージサイズとビルド時間の両面で効きます。
原則9:変更グループ検知でビルド対象を絞る
GitHub Actionsのワークフローで `paths` フィルタを設定し、変更のないジョブは再ビルドしません。開発速度とACRコスト両面で効きます。
原則10:重要ジョブはSlack通知で成功/失敗を可視化
クラウドネイティブのログだけでは気づきにくい失敗(結果が0件だけど例外は出ていない等)をキャッチするために、重要ジョブはSlackに成功/失敗サマリーを通知します。
本番運用で襲ってくる8つの落とし穴
落とし穴1:Beatのタイムゾーン未設定
UTCのままBeatを動かし、9:00 JSTのつもりが9:00 UTC(同日18:00 JST)に動く事故。初日から `Asia/Tokyo` 明示が必須。
落とし穴2:Redis SSLの `ssl_cert_reqs` 省略
Azure Redisで接続が失敗する典型原因。環境の要件に応じた値を明示する必要があります。
落とし穴3:Beatの二重起動
Celery Beatは1プロセスだけが動いていることが前提です。SupervisordやContainer Apps Replicaで複数プロセス走らせると、同じタスクが複数回実行されます。Beat専用の単一インスタンスを明示します。
落とし穴4:ワーカーとBeatの同居起動問題
Supervisordで同じコンテナ内にGunicorn + Celery worker + Celery beatを同居起動する構成は便利ですが、Beatが2つ以上立ち上がる条件では事故が起きます。App Serviceで動かす場合は常に1インスタンスで固定します。
落とし穴5:Azure Container Apps Jobsのリソース割当不足
メモリ不足でOOMkillされて無音で失敗するケース。ジョブごとに適切なCPU/メモリを設定し、監視アラートを組み込みます。
落とし穴6:Managed Identity未設定でAzure API読めない
`DefaultAzureCredential` を使うのに Job Identity が未設定だと権限エラー。最初から `SystemAssigned` を入れます。
落とし穴7:手動 `az containerapp job update` でのdrift
緊急で手動更新した内容がTerraform stateに反映されず、次のdeployで上書き戻りする事故。手動更新後は必ずTerraform stateに同期します。
落とし穴8:ジョブの重複実行(beatとcron両方で登録)
Celery Beatに登録したタスクと、Azure Container Apps Jobsのcronに登録したジョブが重複して同じ処理を実行する事故。役割分担をコードレビューで確認します。
まとめ:Celery BeatとAzure Jobsは「役割分担」で共存させる
FastAPI + Celery + Redis + Azure構成の本番運用は、Celery BeatとAzure Container Apps Jobsのどちらか一方に寄せるのではなく、「アプリと密結合する軽量タスクはBeat、重いバッチ・独立リソース必要なジョブはAzure Jobs」という役割分担で共存させるのが現実解です。SSL対応Redis・テナントタスク自動検出・タイムゾーン明示・Managed Identity・Terraform自動デプロイ・Slack通知の6点を初日から組み込むことで、長期安定運用が可能になります。
renueは、複数のAIエージェント事業を内製運用する中で、この設計パターンを確立してきました。「Celery BeatとAzure Jobsの役割分担を設計したい」「既存のBeat運用で事故が起きていて改善したい」「Azure Container Apps JobsのTerraform化を相談したい」などの具体的ご相談をお受けしています。
renueにCelery + Azure本番運用設計の相談をする
renueは、非同期処理・バッチジョブを含むバックエンドを複数事業で本番運用してきた実体験から、非同期処理・バッチジョブ・スケジューラ設計のご相談に対応しています。設計レビューから本番運用の改善まで、実装粒度でご相談をお受けしています。
関連記事
- マルチテナントFastAPIバックエンド設計2026
- LLMOps実践ガイド2026
- MCP完全ガイド2026
- Function Calling完全ガイド2026
- AI内製化 vs 外注完全ガイド2026
- 生成AIセキュリティ完全ガイド2026
- 生成AI受託開発の費用相場2026
- AIコーディングエージェント徹底比較2026




