【CakePHP3】Dockerローカル開発環境内でGeneral error: 5 database is lockedが発生した時の対処法

Bake-with-CakePHP Logo

Dockerのローカル開発環境でCakePHP3を使った開発をしていると、たまに

General error: 5 database is locked

と表示されてエラー画面が返されることがある。今回はその対処法と原因について紹介する。検証したCakePHPのバージョンは3.6.13。

原因はSQLiteのデータベースロックだった

CakePHP3には、ローカル開発環境でデバッグが容易になるDebug Kitという機能がある。画面右下にCakePHPのケーキマークが出てくるアレのことだ。このDebug Kitは設定を何もいじらないと、SQLiteを使って直近のリクエスト情報を貯めておく性質がある。

↑はtmp配下のディレクトリ構成をls -laしたものだ。debug_kit.sqliteというDBファイルがあるのが分かると思う。

 

General error: 5 database is lockedのエラーメッセージが出た時は上記DBファイルに加えて、debug_kit.sqlite-journalというファイルが生成されている。今回の原因を解消するにはこの2ファイルをmvコマンドで名前を変えるか、あるいは思い切ってrmコマンドで削除してしまえばOK。

参考)https://github.com/cakephp/cakephp/issues/7517

debug_kit.sqliteファイルの役割

debug_kit.sqliteファイルはリクエスト情報を格納しておく簡易DBの役割を果たしている。もしローカル開発環境下でsqlite3コマンドが出来るのであればぜひ下記を試してみてほしい:

↑こんな感じで、SQLiteの内部構成を確認することができる。

SQLiteのjournalファイルとは

SQLiteはMySQLや他のRDBMSと異なり、暗黙のトランザクションとオートコミットを実装している。MySQLでトランザクションをスタート/コミットさせるには明示的にコマンドを打つ必要があるが、SQLiteは勝手にそれをやってくれるわけだ。

 

その性質から、SQLiteに何らかの書き込み処理が発生する時はその書き込み情報を一時的に格納しておくためのjournalファイルが生成される。要は、

journalファイルが存在していると、DBへデータを書き込んでいる最中である

ことを意味している。下記参考サイトで詳細が解説されているので、合わせて参照いただければ理解が深まると思う。

参考)https://www.antun.net/tips/api/sqlite.html

ローカル開発環境のCakePHP3でSQLiteがロックされる原因

CakePHP3のDebug KitがSQLiteにリクエスト情報を書き込む時もjournalファイルが生成されるのだが、たとえば同一ページを瞬間的に何度もリロードしたり別々のページを同時に開こうとする時に今回の問題が発生しやすい。

SQLiteのDBロックがいつまでも解除されずにリクエストの処理待ち状態が続き、最終的にphp.iniで設定されているMaximum execution timeを超えた時にGeneral error: 5 database is lockedのエラーメッセージが出てしまう

ことが起こりうるわけだ。

 

僕の経験上、MacにVagrantを使ったローカル開発環境を構築して開発していた時はGeneral error: 5 database is lockedのエラーに出くわすことは殆どなかったが、Dockerを使ったローカル開発環境に切り替えてからは頻繁にこのエラーに遭遇するようになった感触がある。原因はおそらく、Docker for Macのvolumeマウントの遅さvolumeをマウントする際にcachedやdelegatedの設定を入れれば、多少なり解消する可能性はある。

 

あるいは、SQLiteにリクエスト情報を格納せずにMySQLへリクエスト情報を格納させるという手もありかもしれない。CakePHP3では、Debug Kitにリクエスト情報の格納先を変更させる設定を書くことができる。

参考)https://book.cakephp.org/debugkit/3/ja/index.html#id3