See the Elephant

1992生まれのプログラマが書くエンジニアブログ

mysql server(mysqld)の起動をn回リトライして待つshellコマンドとmakefileを書いた

この記事の対象読者

  • mysql serverの起動を待つスクリプトが欲しい
  • docker-compose で mysqlを使っているが上手く初期化できない

    • なぜか初期化処理がbuildプロセスだけ失敗する
  • 以下のエラーでググってhostを直しても一向に直らない

ERROR 2013 (HY000): Lost connection to MySQL server at 'reading initial communication packet', system error: 0

TL;DR

mysql server(mysqld) の起動を待つ処理を入れましょう。
通常であればこれでいいと思います

$ mysqladmin --wait --count 3 ping || exit 1

docker-composeだとちょっと癖があるので上記以外で対処します。

shellはこんな感じ

for i in 1 2 3 4 5; do mysqladmin ping &>/dev/null && break || sleep 1  && [ 5 -eq $i ] && exit 1; done

人によってはこっちでもいいかも: 処理が成功するまで実行しつづける@katzchang

mysql server(mysqld)の起動を待つshellコマンドとmakefileを書いた

mysql server(mysqld)で起動直後にサーバ接続ができないケースがあった。

困ったので接続できるまでn回リトライし続けるshellコマンドと makefileを書いた。

無限に待ちたいわけではない ので今回は n回 と言う制約を持たせる。

僕はdocker-composeを使っているのでそれ前提で話をすすめる。

同じく困ってる人はいるんじゃないかな、と思ったのでメモる。

docker-compose で mysqlコンテナへ起動直後に接続できない!

今回は docker-composemysqlのコンテナを立てるケースを考える。

コンテナのbuild直後にmysqlに接続できないことがあった。

これでは、buildしたあとにエラーが起きDBの初期化処理が続けてできない。

マイグレーションもできないし、設定もできなくて困る。

コンテナ起動直後はmysql server(mysqld)が立ち上がっていない。

docker container が立ち上がった直後は mysql server(mysqld) がまだ起動していない。

mysql client(mysqladmin) から接続を試みるとこのエラーが出る。

ERROR 2013 (HY000): Lost connection to MySQL server at 'reading initial communication packet', system error: 0

エラーメッセージでぐぐるとhostの設定が足りないとの記事が出てきてめちゃめちゃハマった。

そうじゃない。

sleep n秒が1番簡単な解決方法

マイグレーションなどの処理の前に sleep 60 する

mysql server のデーモン起動(mysqld)まで待てばいいのでこれでok。

起動までリトライしたい

60秒を超えてmysql serverが起動した場合、 sleep 60 だと対応できない。 時間 or n回 リトライするような作りになっていればよい。

How do I write a retry logic in script to keep retrying to run it upto 5 times? より拝借

for i in 1 2 3 4 5; do command && break || sleep 1; done

これを使えば 5回, 1秒ごとに 成功するまでcmdを繰り返す 状態を作り出せる。

mysql serverのlifecheckは mysqladmin ping で行える。

for i in 1 2 3 4 5; do mysqladmin ping && break || sleep 1 ; done

これだと mysql serverが起動してようとしてなろうと次の処理へ行ってしまう。

そこで最終ループのときに exit 1 で抜けるようにした

for i in 1 2 3 4 5; do mysqladmin ping && break || sleep 1 && [ 5 -eq $i ] && exit 1; ; done

makefile で rangeを指定する

build中のタスクランナーとしてmakefileを使っている。

n回処理する記述は以下のように書ける。

RETRY_COUNT=30
RETRY_RANGE=$(shell seq 1 $(RETRY_COUNT) | xargs)

mysql/lifecheck: 
  for i in $(RETRY_RANGE); do mysqladmin ping &>/dev/null && break || echo '.' && sleep 1  && [ $(RETRY_COUNT) -eq $$i ] && exit 1; done

mysql/wait:
  which mysqladmin
   @echo "waiting boot mysql..."
  $(MAKE) mysql/lifecheck