方言を話すおしゃべり猫型ロボット『ミーア』をリリースしました(こちらをクリック)

GolangでデータベースマイグレーションのDirty状態を解決する方法

golang-how-to-solve-dirty-migration
この記事は約7分で読めます。

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ツールを使用している場合:

  1. SELECT * FROM schema_migrations; でDirty状態(dirty = 1)の行を特定。
  2. Dirty状態の行を削除する。
ShellScript
   DELETE FROM schema_migrations WHERE version = '<Dirtyのバージョン番号>';
  1. 状態が正常に戻ったことを確認。

forceの使用方法と注意点

golang-migrateforceコマンドを使うと、指定したバージョンを適用済みとデータベースに記録できる。

ただし、forceは実際のマイグレーションを実行するわけではないため、未適用の状態で指定バージョンに達したとみなされる。必要に応じてupを実行してマイグレーションを完了させる。

forceとupの流れ

  1. 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
  1. 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状態の解消とアプリケーションの起動確認が完了。

タイトルとURLをコピーしました