`supabase/migrations/`に`001_xxx.sql`のような連番でファイルを追加していく。多くのSupabaseプロジェクトで見かける、素朴なやり方だと思う。on-board typingでもそうしていた。ただ、複数の機能を並行して開発していると、この連番が思わぬところで壊れる。
CIが理由もわからず落ちる
Supabase CLIは、適用済みのマイグレーションを`supabase_migrations.schema_migrations`というテーブルに記録している。このテーブルのPRIMARY KEYは、ファイル名の先頭についている番号(バージョン)そのものだ。つまり、`016_a.sql`と`016_b.sql`のように同じ番号のファイルが2つ存在すると、`supabase test db`や`supabase db push`は「duplicate key value violates unique constraint "schema_migrations_pkey"」で必ず失敗する。
厄介なのは、このエラーメッセージだけを見ても、原因がすぐには分からないことだ。マイグレーションの中身自体には何の問題もないのに、CIだけが落ちる。
同じ問題を、3回作ってしまった
一度直せば終わりだと思っていたが、そうはならなかった。複数の機能をそれぞれ別のブランチで並行して作っていると、各ブランチの作業者は、自分のブランチの中でしか「次の番号」を把握できない。ブランチAが019を使い、ブランチBもほぼ同じタイミングで019を使う。それぞれ単体では問題なく通るので、マージするまで衝突に気づけない。
on-board typingでは、この衝突が016番、019/020番、021番と、形を変えて3回続けて起きた。3回目が起きたとき、ようやく「番号のつけ方そのものが並行開発と相性が悪い」と認めることになった。
対策1: 衝突したら、依存順序を保ったまま採番し直す
差し当たりの直し方はシンプルで、後からマージされた方のファイルを、空いている番号にリネームするだけだ。ただし番号は、ファイル名の順序であると同時に実行順序でもある。片方のマイグレーションがもう片方より後に実行される必要がある場合、採番し直すときにその依存関係を壊さないよう注意がいる。
対策2: 重複を機械的に検出できるようにする
その場しのぎの採番し直しを3回繰り返した後、`supabase/migrations/`配下のファイル名から先頭の数字だけを取り出し、重複がないかを確認するチェックスクリプトを作った。中身はシンプルで、ファイル名を数字プレフィックスでソートし、重複だけを抜き出すだけの数行だ。ただ正直に言うと、これをCIに正式に組み込むところまではまだできていない。今は手元で走らせる運用に留まっているので、次にこの手の衝突が起きる前に、CIの中で自動的に落とすところまで持っていくつもりでいる。
そもそも、Supabase CLIは連番を前提にしていない
振り返ってみると、根本的な選択ミスは番号の付け方にあった。Supabase CLIの`supabase migration new
見た目の綺麗さと、並行開発への耐性は、思っていたよりトレードオフの関係にあるようだ。「会社メールで登録するだけ」のようなシンプルな体験の裏側でも、こういう地味な運用の選択が後から効いてくる。on-board typingを支えるSupabase実装の詳細に興味があれば、他の技術記事もあわせて見てみてほしい。