Golangとgolang-migrate
を使ったサーバー開発で、マイグレーションがDirty状態になった場合の対処法をまとめる。Dirty状態とは、マイグレーションが中断し、データベースが不整合な状態になったことを指す。以下に、その解決手順を備忘録的に記載する。
Dirty状態が発生する一般的なケース
Dirty状態が発生するのは、以下のようなケースが多い。
他の開発者が新しいマイグレーションを追加している場合:
- 他の開発者が
develop
ブランチに新しいマイグレーションを追加し、それを適用して作業している。 - 自分のブランチに戻ると、
schema_migrations
の状態とローカルのマイグレーションファイルが一致せず、Dirty状態になる。
マイグレーションの途中で中断した場合:
- エラーや手動での中断により、マイグレーションが正常に完了しなかった結果、Dirty状態になる。
マイグレーションファイルの不整合:
- チーム内で同期が取れておらず、必要なマイグレーションファイルが不足している場合。
テーブルschema_migrationsでDirty状態を解消
Dirty状態を解消するには、マイグレーション情報が格納されているschema_migrations
テーブルを直接修正する。
コマンド
以下のSQLでDirty状態をリセットする。
ShellScript
-- Dirty状態をリセット
UPDATE schema_migrations
SET dirty = FALSE
WHERE version = '<Dirtyのバージョン番号>';
実行例
例えば、マイグレーション番号が20241102
のDirty状態の場合:
ShellScript
UPDATE schema_migrations
SET dirty = FALSE
WHERE version = '20241102';
ターミナルログ例
ShellScript
mysql> UPDATE schema_migrations
-> SET dirty = FALSE
-> WHERE version = '20241102';
Query OK, 1 row affected (0.01 sec)
GUIツールでの手動削除
MySQL WorkbenchなどのGUIツールを使用している場合:
SELECT * FROM schema_migrations;
でDirty状態(dirty = 1
)の行を特定。- Dirty状態の行を削除する。
ShellScript
DELETE FROM schema_migrations WHERE version = '<Dirtyのバージョン番号>';
- 状態が正常に戻ったことを確認。
forceの使用方法と注意点
golang-migrate
のforce
コマンドを使うと、指定したバージョンを適用済みとデータベースに記録できる。
ただし、force
は実際のマイグレーションを実行するわけではないため、未適用の状態で指定バージョンに達したとみなされる。必要に応じてup
を実行してマイグレーションを完了させる。
forceとupの流れ
force
で最新のマイグレーション番号を設定:
Dirty状態を解消した後、指定したバージョンを適用済みとして設定する。
ShellScript
migrate -path <マイグレーションファイルのパス> \
-database "mysql://user:password@tcp(127.0.0.1:3306)/<database_name>" \
force <最新のマイグレーション番号>
ターミナルログ例
ShellScript
2024/11/15 12:00:00 INFO Applying force command
2024/11/15 12:00:00 INFO Forced database to version 20241102
up
で未適用のマイグレーションを実行:force
実行後に残っているマイグレーションを適用する。
ShellScript
migrate -path <マイグレーションファイルのパス> \
-database "mysql://user:password@tcp(127.0.0.1:3306)/<database_name>" \
up
ターミナルログ例
ShellScript
2024/11/15 12:05:00 INFO Applying migrations
2024/11/15 12:05:01 INFO Migration 20241103 applied successfully
2024/11/15 12:05:01 INFO Migration 20241104 applied successfully
実行例
例えば、最新のマイグレーション番号が 20241102
の場合:
ShellScript
migrate -path mia/rdb/migrations \
-database "mysql://user:password@tcp(127.0.0.1:3306)/clocky-db" \
force 20241102
migrate -path mia/rdb/migrations \
-database "mysql://user:password@tcp(127.0.0.1:3306)/clocky-db" \
up
現在のバージョンを確認
現在のデータベースのマイグレーションバージョンを確認する。
コマンド
ShellScript
migrate -path <マイグレーションファイルのパス> \
-database "mysql://user:password@tcp(127.0.0.1:3306)/<database_name>" \
version
ターミナルログ例
ShellScript
2024/11/15 12:10:00 INFO Current database version: 20241102
Docker Composeでの再起動と確認
マイグレーション適用後にDocker Composeを使用してアプリケーションを再起動し、正常に動作していることを確認する。
再起動コマンド
ShellScript
docker-compose down && docker-compose up -d
ターミナルログ例
ShellScript
Stopping clocky-db ... done
Stopping clocky-api ... done
Removing clocky-db ... done
Removing clocky-api ... done
Creating clocky-db ... done
Creating clocky-api ... done
起動状態の確認
以下のコマンドでコンテナの状態を確認。
ShellScript
docker-compose ps
ターミナルログ例
ShellScript
Name Command State Ports
----------------------------------------------------------------------------
clocky-api /bin/sh -c ./start-api.sh Up 0.0.0.0:8080->8080/tcp
clocky-db docker-entrypoint.sh mysqld Up 3306/tcp
- コンテナが
Up
になっていることを確認。 - 必要に応じてログを確認する。
ShellScript
docker-compose logs -f
これでDirty状態の解消とアプリケーションの起動確認が完了。