この資料は、リポジトリに併存する2つのproduction実行方式を比較したものです。Blue-Green Deployment構成はproduction用local blue/green設定、旧構成はsingle production runtime / Compose実装を表します。実ホストには接続していないため、どちらが過去または現在採用されているかは未確認です。
先に結論#
- Blue-Green Deployment構成は、Cloudflare Tunnelの接続先を固定HAProxyに保ち、空slotを準備してから新規要求の行き先を切り替えます。
- AI Worker containerは平常時1つ、更新中だけ新旧2つです。各container内では3種類の論理processorが動きます。
- 切替後も旧Webは接続数が0になるまで、旧Workerは旧releaseのAI処理が全て完了するまで残します。
- 旧・単一runtime構成は、Web/APIとAI Workerが1つのcombined processで動きます。更新時は旧containerを停止・削除した後に新containerを起動するため、blue/greenの同時稼働やdrainはありません。
- 停止時間を生じさせない切替の対象は、同じmigrationVersionで行う通常リリースです。可用性SLAや実環境での実績を示すものではありません。
1. Blue-Green Deployment構成#
AI Workerはいくつか#
- 平常時は1 containerです。active slotにWeb 1 containerとAI Worker 1 containerが動き、もう一方のslotは空です。
- 更新中だけ2 containersです。candidate slotのAI Workerを先に起動するため、旧releaseと新releaseのWorkerが一時的に並行稼働します。
- 1つのAI Worker process内では、durable feedback worker、durable AI generation worker、production command materializerの3 processorを起動します。したがって、1 containerで同時に1 jobしか処理できないという意味ではありません。
通常の更新は次の順序です。
- 現在使われていないslotで、新releaseのAI Worker containerを起動し、続いてWeb containerを起動する。
- WebとWorkerの認証済みreadiness成功を連続3回確認する。
- HAProxyのweightを変更し、新規要求をcandidate slotへ一括で切り替える。
- 旧Webへの新規流入を止め、既存接続が0になるまでdrainする。
- 旧Workerは旧release向けのAI処理が0になるまで残し、その後に旧slotを回収する。
PostgreSQLは新旧slotが共有する正本です。業務データ、session、永続queueをcontainer外に置き、WorkerはreleaseVersionに対応するjobをclaimします。旧slotを保持している間は、HAProxyを戻すrollback経路もあります。
AI処理中に更新した場合#
- 切替前に開始されたAI処理は、旧Workerが旧releaseの契約のまま継続します。新WorkerはreleaseVersionが一致する新release側のjobを担当し、旧jobを横取りしません。
- 通常のreaperは、旧releaseについてbackground job、実行中attempt、command execution、OpenAI provider leaseの4項目を確認します。
- 4項目が全て0になるまで旧Worker containerを残し、
drained=trueになってから停止します。 - Worker containerにはshutdown mode
drainが設定されます。generation/feedback処理は停止signal時も実行中controllerをabortせず、command materializerも実行中promiseの完了を待ちます。
したがって、通常のBlue-Green Deploymentでは、OpenAIへ要求中という理由だけで旧Workerを直ちに終了しません。ただし、強制kill、host停止、電源断、drain timeout、外部provider障害まで処理完了を保証するものではありません。
適用範囲#
- 通常deployでは現在とcandidateの
migrationVersionが同一である必要があります。異なる場合はdeployが拒否されます。 - 非互換なDB変更は通常切替に含めず、計画停止を伴うmigrationとして扱います。
- 単一runtimeからblue/greenへ初めて移行する際は、1回限りの計画停止が必要です。
- 切替中は新旧slotを同時に動かすため、アプリ部分はおおむね2倍のresourceを必要とします。
- drain timeoutや外部依存障害まで無停止を保証する図ではありません。実稼働の可用性はhost、HAProxy state、container、監視記録で別途確認が必要です。
2. 旧・単一runtime構成#
deploy/production/host-runtime.mjs は、単一のSaaS containerをloopback :3000 で管理します。runtime roleを指定しない場合はcombinedとなり、Next.js Web/APIとdurable AI Workerが同じprocessで起動します。
更新または再起動の流れは、既存のcloudflaredとcontainerを停止し、既存containerを削除してから、新containerを作成・起動し、readiness成功後にcloudflaredを開始する順序です。したがって、更新中に新旧アプリを並行稼働させるslotや、旧processを段階的にdrainする仕組みはありません。
AI jobの正本がPostgreSQLにあることは、process停止とデータ消失が同義ではないことを意味します。一方でcombined process自体は停止するため、その間のWeb受付とWorker実行は連続しません。この図は停止時間やデータ損失の実績を示すものではありません。
比較表#
| 観点 | Blue-Green Deployment構成 | 旧・単一runtime構成 |
|---|---|---|
| 公開入口 | Tunnel → 固定HAProxy :3001 | Tunnel → 単一container :3000 |
| アプリ実行単位 | active slotにWeb ×1 + AI Worker ×1 | Web/APIとWorkerを含む1 combined container |
| AI Worker container数 | 平常時1、更新中のみ新旧2 | 平常時1。更新時は旧を停止後に新を起動 |
| Worker内processor | feedback、generation、command materializerの3系統 | 同じ3系統がcombined process内で動作 |
| 更新前の準備 | 空slotを起動しreadinessを確認 | 旧containerを先に停止・削除 |
| トラフィック切替 | HAProxy weightで新規要求を一括切替 | 新container readiness後にTunnel開始 |
| 旧Web | 新規流入を止め、接続0までdrain | container停止時に終了 |
| AI処理中の更新 | 旧Workerが旧release処理を完了。drained確認後に停止 | combined process停止時に終了。既定のshutdown drainはOFF |
| rollback | 旧slot保持中にHAProxyを戻せる | 新旧の同時保持を前提とした切替はない |
| DB | 新旧slotで共有するPostgreSQL | container外のPostgreSQL |
| 通常更新の制約 | 同一migrationVersion。非互換DB変更は計画停止 | blue/greenのmigration gateなし |
| 実稼働確認 | 未確認 | 採用履歴・実稼働とも未確認 |
根拠#
- Blue-Green Deploymentの全体手順と制約:
docs/operations/bluegreen/local-bluegreen-deployment.md:3-38,40-47(R041) - production slot・port・drain設定:
config/local-bluegreen.production.example.json:1-52(R042) - Web/Worker container分離とworker drain mode:
deploy/local-bluegreen/local-bluegreen.mjs:26,232-294(R043) - candidate起動、readiness、HAProxy切替、旧slot回収、rollback:
deploy/local-bluegreen/local-bluegreen.mjs:583-688,985-1050,1177-1236(R044) - 単一containerのcombined role、停止・再作成、readiness、Tunnel起動:
deploy/production/host-runtime.mjs:29-45,65-72,98-140(R045) - role未指定時のcombinedとshutdown drain既定値:
okr-cai-saas/src/lib/runtime-role.ts:1-33(R046) - Worker process内の3 processor起動:
okr-cai-saas/src/instrumentation.ts:9-44(R047) - 単一SaaS serviceとPostgreSQL:
compose.yaml:1-121(R048) - 旧releaseのdrained判定:
okr-cai-saas/src/lib/db/postgres/runtime-control.ts:170-240(R049) - generation workerのrelease fenceとshutdown drain:
okr-cai-saas/src/lib/ai/generation-job.ts:540-555,1979-2011(R050) - feedback workerのrelease別claimとshutdown drain:
okr-cai-saas/src/lib/ai/feedback-job.ts:235-332,950-971(R051) - command materializerのrelease別claimと完了待ち:
okr-cai-saas/src/lib/ai/production-command-job.ts:557-593,869-900(R052)

