Open1

【BackEnd】Server側のバックグラウンド処理実装について📝

まさぴょん🐱まさぴょん🐱

サーバー側で「バックグラウンドで処理する」ための考え方と代表的な実装方法

なぜバックグラウンド処理を分離するのか

  • API 応答を速く保つ – フロントエンドや他サービスがタイムアウトしにくい
  • スケールの自由度 – ワーカーだけを横に増やして重い処理をさばける
  • 再試行や遅延実行が簡単 – キューに任せればリトライ・レート制限・DLQ(死活キュー)が標準で使える

主なパターン

パターン 適したケース メリット / 注意点
同一プロセス内の軽量処理
ctx.waitUntil()(Cloudflare Workers)/ Promiseawait しない
ログ追加・分析イベント送信などミリ秒級の処理 すぐ書けるが、CPU を共有し再起動で失われる
Node.js Worker Threads / child_process CPU バウンド処理(画像変換など)を自コンテナ内で分けたい 外部サービス不要。クラッシュ監視や水平スケールは自力
自前ジョブキュー(Redis/Mongo など)
例: BullMQ(Redis), Agenda(MongoDB), Bree(ファイル + Worker Threads)
数千〜数万件/分規模、クラウドに依存したくない場合 リポジトリ内で完結。Redis や Mongo の運用が必要
マネージドキュー+ワーカー
Cloudflare Queues, Google Cloud Tasks, AWS SQS + Lambda, Supabase Edge Functions
インフラ運用を極力減らしたい、オートスケールしたい インフラはお任せ。課金体系とベンダーロックに注意
スケジュール/Cron 系
Agenda, Bree, Cloudflare Cron Trigger など
毎時・毎日レポート生成、定期バッチ 書式がシンプル。長時間ジョブはキューと併用

Hono(Node ランタイム)の典型的な構成例

  1. エンドポイント側 (api.ts)

    const q = new Queue("patent-search", { connection: { host: "redis" } });
    
    app.post("/search", async (c) => {
      const { query } = await c.req.json();
      const job = await q.add("run_search", { query });
      return c.json({ jobId: job.id, status: "PENDING" });
    });
    
  2. ワーカー側 (worker.ts)

    new Worker("patent-search", {
      connection: { host: "redis" },
      concurrency: 5,
      processor: async (job) => { /* 検索ロジック */ }
    });
    
  3. DB にステータス保存/status/:jobId でフロントがポーリングや SSE。


代表的ライブラリ/サービス早見表

目的 小規模・手軽 プロダクション高負荷 マネージド完全自動
すぐ動かす Bree(依存ゼロ) BullMQ(Redis) Cloudflare Queues + Worker
Cron 的処理 Agenda(Mongo) 同左 Cloudflare Cron Trigger / Cloud Scheduler
GCP 環境 Redis + BullMQ on Cloud Run Cloud Tasks + Cloud Run
AWS 環境 Redis + BullMQ on ECS SQS + Lambda

選定のヒント

  • 既に Redis を運用 → BullMQ が王道。UI(bull-board)も付けられる
  • エッジに寄せたい/グローバル低遅延 → Cloudflare Workers + Queues
  • GCP ネイティブで完結 → Cloud Tasks は IAM・HTTP 認証込みで便利
  • バッチ主体で DB は Mongo → Agenda がシンプル

実装時の注意点

  1. 冪等性 – リトライされても二重実行にならない設計(DB に一意キー/version カラムなど)
  2. 監視・可視化 – 処理時間、失敗数をダッシュボード化(BullMQ UI, Cloud Logging 等)
  3. シャットダウン – ワーカーは SIGTERM を受けたら現在のジョブを終えてから終了する

ブラウザ Service Worker との違い

Service Worker (ブラウザ) サーバー/ワーカー
主目的 オフラインキャッシュ・プッシュ通知 バックエンド非同期ジョブ
実行場所 ユーザー端末 サーバー or クラウド
トリガー fetch, push, sync イベント キュー投入、Cron、Webhook など

今後の進め方(おすすめ)

  1. ローカル Docker Compose で Redis + BullMQ を試し、開発環境に組み込む
  2. 軽微なバックグラウンド作業は Cloudflare Workers 部署時に ctx.waitUntil() を使う
  3. サービスが成長したら Cloudflare Queues または Cloud Tasks へ移行し、ワーカーだけを横に増やす

これで「API は即レスポンス」「重い処理は安全に並列化」という構成を段階的に取り入れられます。