手順は docs/architecture/23-ops.md のセクション 7 と docs/architecture/07-data.md のセクション 4.1 にあります。以下が作業手順です。
安全性を保証する仕組み
リリース R はスキーマ R と R-1 の両方で正しく動作します。 スキーマ変更は拡張、移行、縮約の 3 段階に分けます。
- 拡張: 新しい列、テーブル、インデックスを追加します。古いコードは無視します。
- 移行: 少なくとも 1 リリースの間、新しいコードは新旧両方の形式を書き、新形式を読み取ります。再開可能なジョブで古い行を埋めます。
- 縮約: 旧形式を後続リリースで単独で削除します。
そのためローリングアップグレード中も、旧プロセスと新プロセスが同じデータベースを使えます。ダウンマイグレーションはありません。1 時間前に列を削除するマイグレーションを戻しても、その 1 時間に書き込まれた行は復元できないためです。
schema-compat CI ジョブは、旧リリースのテストを新しいスキーマに対して実行し、すべてのリリースでこの保証を確認します。
開始前
- リリースノートを読みます。メンテナンス時間が必要なリリースでは所要時間が記載されます。1 リリースにつき最大 1 回です。
- 復元ドリルを実行するか、このリリースで成功済みであることを確認します (backup-restore.md)。ドリルが失敗した場合はアップグレードできません。
- ベースバックアップを作成します。
docker compose -f docker/compose.yaml --profile backup run --rm backup
Docker Compose、単一ホスト
export QUIRE_RELEASE=2026.10.0 # or set it in docker/.env
docker compose -f docker/compose.yaml pull # or build
docker compose -f docker/compose.yaml run --rm migrate
docker compose -f docker/compose.yaml up -d --no-deps web content collab
docker compose -f docker/compose.yaml up -d --no-deps worker scheduler実行順序には理由があります。
- 旧リリースがトラフィックを処理している間に、先にマイグレーション を実行します。拡張マイグレーションは旧コードから見えません。
- 次に Web 層 を更新します。SIGTERM を受け取ると各 Web プロセスは
/readyzをdrainingにし、処理中のリクエストを 30 秒以内に完了し、再接続を促すヒントとともにストリームを閉じて終了します。stop_grace_periodは 40 秒なので、Compose が正常な停止処理を中断することはありません。 - worker は最後 に更新します。新しいイベント形式を先に生成し、次に新しい形式を期待する consumer を動かすためです。worker はすぐにジョブ取得を止め、120 秒間処理を続けます。完了できないジョブは他の場所で再取得されます。すべてのジョブが冪等なので安全です。scheduler は次の起動時にリーダーを引き継ぎます。
単一ホストでは Compose が各コンテナを順番に置き換えるため、サービスごとに短い停止があります。停止をなくすには、独自プロキシの背後で Web 層を 2 コンテナ実行します (公開ポートなしの 2 つ目の Web サービスをオーバーライドファイルで追加)。正常状態を確認してから 1 つずつ再作成します。
複数ホストまたはオーケストレーター
同じ順序で実行します。1 つのジョブで一度だけマイグレーションし、Web 層は追加台数 1、利用不能台数 0 で段階的に更新してから worker を更新します。準備状態プローブは /readyz、生存状態プローブは /healthz を使います。
テナントごとの専用 DB がある場合、migrate はまず制御 DB を移行し、次に ops.tenant_database にある各 DB を個別のロックを取得して順番に移行します。1 つのテナント DB が失敗しても他は続行します。すべて完了した後、マイグレーション履歴を比較し、制御 DB と同じマイグレーションが適用されていない DB を列挙して、終了コード 0 以外で終了します。worker は固定テナントのジョブを登録先 DB から処理するため、同じコマンドで各 DB のキューテーブルも作成します。
bun apps/worker/src/migrate.ts # what the Compose step runs
bun run db:migrate:all # the same, from a checkout各専用 DB には登録名で接続します。env:QUIRE_DB_NORTHWIND_URL として登録した DB には次が必要です。
| 変数 | 用途 |
|---|---|
QUIRE_DB_NORTHWIND_URL |
Web 層と worker 用アプリケーションロール |
QUIRE_DB_NORTHWIND_URL_MIGRATOR |
このコマンドと移動処理用の migrator ロール |
QUIRE_DB_NORTHWIND_URL_SUPERUSER |
任意。マイグレーション前に初期設定 (ロール、スキーマ、ヘルパー) を再適用 |
_MIGRATOR 接続のない登録済み DB はスキップせず、失敗として報告します。制御 DB の移行後に Web 層を更新できます。テナント DB の遅れが 1 時間なら警告、1 日ならページ通知です。
pgvector
マイグレーション 0264 以降、サーバーに拡張機能がある場合、grounding コーパスでは pgvector HNSW インデックスを使います。Compose の postgres サービスは拡張機能込みでビルドされます (docker/postgres.Dockerfile)。イメージ切り替え後の最初の migrate は superuser bootstrap で拡張機能を作り、0264 が生成ベクター列を追加してインデックスを構築します。列の追加では排他ロックのもと app.ai_chunk を一度書き換えるため、grounding のリクエストはその間待機します。他の処理はこのテーブルを使いません。
pgvector がないサーバーでは 0264 は通知をログに記録して何も変更せず、検索は正確検索のままです。pgvector が 0.8 より古い場合、列とインデックスは作成されますが、拡張機能を更新 (alter extension vector update) するまで正確検索を使います。フィルター付き HNSW スキャンには 0.8 の反復スキャン機能が必要だからです。未導入サーバーで後から有効にするには、拡張機能をインストールし、bootstrap を再実行する (または superuser で create extension vector を実行する) か、quire_migrator として次を実行します。
set maintenance_work_mem = '1GB'; -- the HNSW build is much faster in memory
select ops.ai_chunk_enable_vector_index();冪等な処理で enabled または unavailable を返します。各専用テナント DB でも実行してください。
ロールバック
コード のロールバックはいつでも可能です。QUIRE_RELEASE を前のタグに戻して up -d を実行します。リリース内ではスキーマが前後どちらのバージョンにも互換性を持つためです。
スキーマ のロールバックはできません。取り消せない変更と復旧方法は次のとおりです。
| 元に戻せないもの | 復旧方法 |
|---|---|
| 列を削除した縮約マイグレーション | 削除前の時点に新しい DB へ復元し、データを抽出して統合 |
| インプレースのデータ変更 | 同様に復元し、その後の書き込みを調整 |
| 送信済み webhook とイベント | 削除せず、補償イベントを送信 |
| 送信済みメール | 人がフォローアップを書く |
| 監査ハッシュチェーン | 書き換えず、訂正エントリを追加 |
そのため縮約マイグレーションは単独リリースにします。復元時に明確な境界を保てます。
アップグレードの確認
docker compose -f docker/compose.yaml ps # every service healthy
curl -fsS http://localhost:8080/readyz # ready, and what is configured
docker compose -f docker/compose.yaml logs migrate # the migrations applied