この記事の対象読者
-
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はこんな感じ
// 5回繰り返す
for i in 1 2 3 4 5; do mysqladmin ping &>/dev/null && break || sleep 1 && [ 5 -eq $i ] && exit 1; done
// 出来るまで繰り返す
until (mysqladmin ping &>/dev/null) do echo '.' && sleep 1; done
人によってはこっちでもいいかも: 処理が成功するまで実行しつづける@katzchang
makefile
mysql/lifecheck:
until (mysqladmin ping &>/dev/null) do echo '.' && sleep 1; done
mysql/wait:
which mysqladmin
@echo "waiting boot mysql..."
$(MAKE) mysql/lifecheck
mysql server(mysqld)の起動を待つshellコマンドとmakefileを書いた
mysql server(mysqld)で起動直後にサーバ接続ができないケースがあった。
困ったので接続できるまでn回リトライし続けるshellコマンドと makefileを書いた。
無限に待ちたいわけではない ので今回は n回
と言う制約を持たせる。
僕はdocker-composeを使っているのでそれ前提で話をすすめる。
同じく困ってる人はいるんじゃないかな、と思ったのでメモる。
docker-compose で mysqlコンテナへ起動直後に接続できない!
今回は docker-compose
でmysqlのコンテナを立てるケースを考える。
コンテナの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
無限に続ける方はこっち。こっちの方が仕事が明確
mysql/lifecheck:
until (mysqladmin ping &>/dev/null) do echo '.' && sleep 1; done
mysql/wait:
which mysqladmin
@echo "waiting boot mysql..."
$(MAKE) mysql/lifecheck