DB の版を上げる手引き

版は起動時に自動で当たる。本番へ当てる前に、写しで予行する

📅 作成: 2026-09-02 / 更新: 2026-09-04

DB の形を変えるときは src/scripts/20_migrate/ver_NNNNNN/*.sql を足す。起動時に足りない分だけが当たるので、当てる操作は要らない。仕組みは設計の版管理の章にある。

この手引きは本番の DB に当てるときの手順だけを書く。

目次

  1. 当てる前に予行する
  2. 本番に当てる
  3. つまずいたとき

当てる前に予行する

本番の写しで予行してから当てる。いきなり本番へ当てない。

版の SQL は当て済みの環境では二度と実行されない。失敗すれば巻き戻るが、当たったあとで間違いに気づいても、その版を書き換えることはできない(指紋が食い違って起動が止まる)。新しい版で打ち消すしかなくなる。

1. 控えを取る

node tools/80_ops/snapshot.mjs ver3
相手: .\_data\chat.db
控え: .\_backup\20260902-070632-ver3.db
取りました:
  messages   : 77 件
  connectors : 8 件
  cursors    : 8 件
  版         : 2

VACUUM INTO で取るので 1 ファイルで完結する。-wal に残っている分も本体に統合される。サーバーは止めなくてよい。

取れたことと、中身が入っていることは別である。snapshot.mjs は取ったあとに控えの側を数えて出す。件数が 0 なら本体だけを写しているので、そのまま進めない。

2. 写しをテスト環境へ置く

$dir = './tmp/_data/rehearsal'
New-Item -ItemType Directory -Force $dir
Copy-Item '_backup/20260902-070632-ver3.db' (Join-Path $dir 'chat.db')

控えをそのまま使う。本番の chat.db を直接コピーしない。-wal を置いてくることになり、写した先の中身が本番と違う。

3. 予行する

$env:AICHAT_DATA = './tmp/_data/rehearsal'
$env:AICHAT_PORT = '8796'
node src/server/main.mjs

起動のログに版が上がったことが出る。

DB の版を上げます: 2 → 3
版を上げる前の控えを取りました: .\tmp\_data\rehearsal\pre-ver-000002-20260902070715.db
DB の版を 2 から 3 へ上げました
通常の応答に切り替えました
確かめることやり方
版が上がったか起動ログ。versions テーブルにも記録される
中身が残っているか件数を上げる前と見比べる。発言・参加者・読んだ位置
既存の発言が読めるかrecent で直近を出す
新しい機能が動くかその版で足したものを実際に使ってみる

4. 全テストを流す

node --test tests/

1 件でも落ちたら本番へ進まない。予行が通っても、テストが落ちるなら形が想定と違っている。

本番に当てる

版は起動時に当たるので、やることは「落として、また起動する」だけである。ただし落としている間に手を入れる必要があるときは、印を置いて止める。

そのまま起動し直すだけでよいとき

aichat restart :project-a: -p 8787

終了コード 1 で落ちるため、サービスが 10 秒後に起動し直す。その起動で版が当たる。

落としている間に手を入れたいとき

印を置くと、サービスが起動し直しても DB を開かずに待つ。その間に作業できる。

#やること
1_data\MAINTENANCE を作る。中身に理由を書くと /api/version に出る
2chat.mjs restart で落とす
3DB が離されたことを確かめる(ファイルが開けるか)
4作業する
5印を消す。数秒で自分から起動し、版が当たる

止まっている間もポートは開いている。/api/version は 200 で理由を返し、それ以外は 503 になる。待受け中のクライアントは 10 分粘って繋ぎ直すので、短い作業なら誰も気づかない

再開すると public に「運用を再開しました。約 N 分止まっていました」と流れる。読んだ位置は保たれているので取りこぼしはない。

当たったことを確かめる

node src/client/chat.mjs recent -n 3 -p 8787

件数を上げる前と見比べる。発言が 1 件増えているのは、再開の案内が積まれたためである。

つまずいたとき

当てるのに失敗した

失敗: ver_000003 を当てられませんでした: table archives already exists

1 つの版は 1 つのトランザクションで当たる。途中で失敗すれば巻き戻り、版も上がらない。DB は壊れない。

ただし main.mjs はここで例外を投げるため、サーバーが起動しない。サービスが再起動を繰り返す状態になるので、印を置いて止めてから原因を直す。

形が揃っていないと言われる

DB の形が揃っていません(足りないテーブル: messages cursors connectors archives)。
版を当ててから開いてください。

store.mjs は形を作らない。版の SQL だけが形の出どころで、store.mjs は開いたときに揃っているかを確かめるだけである。版を当てる前に読み込むと、ここで止まる。

どこから読んだかやること
サーバー(main.mjs起動時に migrate() が走るので、通常は出ない。出たら版の SQL を疑う
テストtests/helpers/prepare-db.mjsprepareTestDb() を、store.mjs を読み込む前に呼ぶ
手元の確認node -e "import(…)" のような読み込みは止まるのが正しい。置き場を指定して版を当ててから読む

かつては読み込むだけで DB ができていた。store.mjsCREATE TABLE IF NOT EXISTS があった頃、AICHAT_DATA を立てずに読み込むと本番の DB にテーブルが作られた。

実際に起き、版 3 で足すはずの archives が先にできてしまい、版 3 を当てると「already exists」で止まる状態になった(i260902-01)。いまは止まるので、同じことは起きない。

版の SQL を IF NOT EXISTS に書き換えて逃げない。指紋が変わるため、すでに当て済みの環境(テスト環境など)で「書き換えられています」と出て起動が止まる。

当てたあとで間違いに気づいた

状況やること
まだ本番へ当てていない その版を直してよい。当て済みのテスト環境は DB を作り直す
本番へ当てた 新しい版で打ち消す。当てた版は書き換えない
中身が壊れた 控えから戻す。バックアップの手引きを見る

下り(元に戻す SQL)は持たない。戻すなら控えから戻す。SQLite では列の削除もできず、下りを正しく書き続けるのは重い。