Laravelでデータベース接続のリトライ
2017/12/26追記
業務で組み込んでみましたが、他と組み合わせるとうまく動かず。。 もし、解決策が分かったら更新します。。
久々の投稿です。あまり情報が載ってなかったので。。
目的
LaravelでDB接続リトライを指定回数行えるようにしたい
背景
今度お仕事でLaravelというPHPフレームワークを使うことになりました。
要望として、DB接続ができなかった場合に何回かリトライして欲しいとのことでした。
本題
いろいろ試行錯誤はしましたが、結論だけ書きます。
Laravelにはファサードという仕組みがあります。
ファサード 5.5 Laravel
公式サイトによると、「db」という文字列をファサードを利用して設定することにより、
DatabaseManagerクラスの差し替えが可能らしい。
ファサード 5.5 Laravel
さらに、実際にDB接続を失敗させてみたExceptionのスタックトレースを見ると、
DatabaseManager#__call
というメソッドがreadのときもwriteのときも呼ばれている模様。
overrideしてこのメソッドでリトライしてあげれば良さげ。
(ここはちょっと自信ありません。試してみた結果だし、アンスコ2個付いてるメソッド名だし。。(でもpublicだし))
で書いたclassがこちら。
<?php namespace App; use Exception; use Illuminate\Database\DatabaseManager; use Illuminate\Support\Facades\Log; class DBManager extends DatabaseManager { function __call($method, $parameters) { $i = 0; while (true) { try { $i++; return parent::__call($method, $parameters); } catch (Exception $e) { Log::warning("Connection failed..."); if ( $i >= 3 ) { throw $e; } Log::warning("Retry!"); } } return null; } }
(3ってマジックナンバーだけどお仕事の時はちゃんとconfigから読むようにしますよ。)
まだクラスを作っただけなのでLaravelとは関連付けられてません。
今回は AppServiceProvider#register
にて関連付け(差し替え)を行いました。
public function register() { $this->app->singleton('db', function ($app) { return new DBManager($app, $app['db.factory']); }); }
singletonというメソッド指定はLaravel内部でそういう指定の仕方をしているため。
(ここも公式ドキュメントに載せてほしいなあ。。)
github.com
DB接続を失敗させてみます。 ※今回はDebugBarで確認しています。
ちゃんとリトライするようになりました。
まとめ
本当にこれで正しいのか分からないのでツッコミ待ちですが、
一旦はこれで要件は満たせそうです。