DB の形を変えるときは src/scripts/20_migrate/ver_NNNNNN/*.sql を足す。起動時に足りない分だけが当たるので、当てる操作は要らない。仕組みは設計の版管理の章にある。
この手引きは本番の DB に当てるときの手順だけを書く。
本番の写しで予行してから当てる。いきなり本番へ当てない。
版の SQL は当て済みの環境では二度と実行されない。失敗すれば巻き戻るが、当たったあとで間違いに気づいても、その版を書き換えることはできない(指紋が食い違って起動が止まる)。新しい版で打ち消すしかなくなる。
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 なら本体だけを写しているので、そのまま進めない。
$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 を置いてくることになり、写した先の中身が本番と違う。
$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 で直近を出す |
| 新しい機能が動くか | その版で足したものを実際に使ってみる |
node --test tests/
1 件でも落ちたら本番へ進まない。予行が通っても、テストが落ちるなら形が想定と違っている。
版は起動時に当たるので、やることは「落として、また起動する」だけである。ただし落としている間に手を入れる必要があるときは、印を置いて止める。
aichat restart :project-a: -p 8787
終了コード 1 で落ちるため、サービスが 10 秒後に起動し直す。その起動で版が当たる。
印を置くと、サービスが起動し直しても DB を開かずに待つ。その間に作業できる。
| # | やること |
|---|---|
| 1 | _data\MAINTENANCE を作る。中身に理由を書くと /api/version に出る |
| 2 | chat.mjs restart で落とす |
| 3 | DB が離されたことを確かめる(ファイルが開けるか) |
| 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.mjs の prepareTestDb() を、store.mjs を読み込む前に呼ぶ |
| 手元の確認 | node -e "import(…)" のような読み込みは止まるのが正しい。置き場を指定して版を当ててから読む |
かつては読み込むだけで DB ができていた。store.mjs に CREATE TABLE IF NOT EXISTS があった頃、AICHAT_DATA を立てずに読み込むと本番の DB にテーブルが作られた。
実際に起き、版 3 で足すはずの archives が先にできてしまい、版 3 を当てると「already exists」で止まる状態になった(i260902-01)。いまは止まるので、同じことは起きない。
版の SQL を IF NOT EXISTS に書き換えて逃げない。指紋が変わるため、すでに当て済みの環境(テスト環境など)で「書き換えられています」と出て起動が止まる。
| 状況 | やること |
|---|---|
| まだ本番へ当てていない | その版を直してよい。当て済みのテスト環境は DB を作り直す |
| 本番へ当てた | 新しい版で打ち消す。当てた版は書き換えない |
| 中身が壊れた | 控えから戻す。バックアップの手引きを見る |
下り(元に戻す SQL)は持たない。戻すなら控えから戻す。SQLite では列の削除もできず、下りを正しく書き続けるのは重い。