SQLiteを1経路で作る
配信用の SQLite ファイル(dev.db)を、中継のクラウドDBを挟まずに
データレイク(Iceberg)から直接作る構成の記録。
stock-app で実際に切り替えたときに踏んだ挙動を書く。
経緯は経路を1本に減らしたら、消えていた索引が出てきた。
経路の形
中継DBを外すと何が消えるか
| 消えるもの | 理由 |
|---|---|
| HTTPクライアント一式 | リモートへ送らないので不要 |
asyncio | HTTP往復を並行化するためだけに使っていた。同期化できる |
| ローカル/リモートの分岐 | 送信先が1つになる |
| スキーマ整合の同期スクリプト | マイグレーションが直接当たるので不要 |
手書きの MIGRATIONS 配列 | 上と同じ。これが歯抜けの原因になる |
| 疎通確認・スロットリング用スクリプト | 送信先が無くなれば宛先も無い |
踏んだ挙動
1. マイグレーションの適用先が抜けて、索引が消える
生成経路を差し替えたとき、db/migrations/ を当てる段が経路から落ちた。
- 症状: ページは正常に表示される。エラーもログも出ない。特定のクエリだけ遅い
- 原因: 索引が1つ作られておらず、インデックスを使うはずのクエリが全走査(SCAN)へ退行していた
- 見つけ方:
EXPLAIN QUERY PLANでSCANになっていないか見る。 索引の有無はPRAGMA index_list(<テーブル>)で数える - 対処: 生成経路の先頭でマイグレーションを全件適用する。 「新しいファイルだから最新のはず」という前提を置かない
経路を差し替えるときは、経路上の段を1つずつ数える。 新しい経路が通ったことと、旧経路がやっていた仕事が全部移ったことは別。
2. 0件で静かに完了する
対象テーブルが存在しない状態でエクスポートを走らせると、 書き込む先が無いだけで例外にはならず、0件のまま正常終了する。 そのまま配信すると、空のファイルが本番へ出る。
対処は、エクスポート開始時に対象テーブルの存在を検査して、 無ければ異常終了させること。件数0を成功として扱わない。
起動 → 対象テーブルが全部あるか確認 → 無い → 非ゼロで終了
「何も起きなかった」と「うまくいった」を、終了コードで区別できるようにしておく。
3. 手書きの配列は必ず歯抜けになる
適用すべきマイグレーションを配列に列挙する形にしていると、 マイグレーションを足した人が配列に書き足すのを忘れた時点で黙って壊れる。 ディレクトリを読んで全部当てる形にすれば、書き忘れる場所自体が無くなる。
ゼロから作り直す
作り直せるかどうかは、テーブルごとに正本がどこにあるかで決まる。
| 種類 | 正本 | 戻し方 |
|---|---|---|
| データレイクが正本のテーブル | Iceberg | マイグレーション全適用 → エクスポートの2コマンド |
| 外部取得で組み立てるテーブル | 外部API | 専用のブートストラップスクリプトで再生成 |
| 計算結果のテーブル | 計算処理 | 再計算のバッチを流す |
全部戻せる。ただし実運用で壊れたときの最短復旧は、配信先に置いてある スナップショットを戻すことで、再生成は最短ではない。 設計ドキュメントには「戻せるか」と「戻すのが速いか」を分けて書く。
注意点
- 中継DBを外すと、手元と本番で同じファイルを見ることになる。 手元での生成が本番の中身そのものなので、生成の失敗は即配信の失敗になる
- 生成時間は往復が消えた分だけ短くなるが、 効いているのはHTTPのレイテンシであってDBの速さではない
- 配信の無料枠にはサイズ上限がある。経路を1本にしても、 出力サイズの監視は別途要る