November 14, 2021 • ☕️ 5 min read
【 環境 】
Laravel のバージョン: 8.16.1
PHP のバージョン: 7.4.7
MySQL のバージョン: 5.7
表題の通り。
Laravel でスケジューラからコマンド実行する場合、内部的にはキャッシュドライバを使用しています。(開発者として意識されていない方もいるかとは思いますが。明示されているワケではないし、わざわざ調べないと行きつかない事なので。)
詳しくは、以下をご参照ください。
【Laravel】Schedule の onOneServer って、どんな動きをしているの? Laravel のソースコードを追ってみた。
【Laravel】schedule の onOneServer メソッドを使うと、スケジューラが安定しない? キャッシュドライバが原因かもしれません。
キャッシュドライバには Redis が使われる事が多いですが、スケジューラを回す場面においては、それがとんでもない辛みを生み出していたので、今回のプロジェクトではキャッシュドライバを RDB に変えました。
ちなみに、私一人が辛みを抱えて独断で決行したという訳ではなく、同じように苦しめられているメンバーが居て、彼と相談しつつ設定を変え、安定稼働した後も「やっぱキャッシュドライバを RDB に変えて正解だったね。」と話をしました。
スケジューラからコマンドを叩く時、こんな感じでメソッドを並べていくかと思います。
$schedule->command(Batch01Command::class)
->everyMinute()
->runInBackground()
->withoutOverlapping()
->onOneServer()
->onSuccess(function () {
\Log::info('Batch01Command successful.');
})
->onFailure(function () {
\Log::info('Batch01Command failed.');
});
これらのメソッドの細かい挙動を把握しておられますでしょうか。
このブログでは、Laravel のスケジューラ周りについては結構書いてて、エントリ数もそれなりの数になりました。
というか、ここまで調べておかないと、挙動を把握して安定稼働させる事が出来なかったのです。
(スケジューラによるバッチ処理がメインのシステムで、それらが複雑に絡み合っている、という側面もありますが。)
頻繁に起こっていたのが、「スケジューラは動いているのに、コマンド(ジョブ)が実行されない」という現象でした。
ちなみに、ローカル環境ではそんな事は特に発生せず、AWS環境のみで発生する事象でした。
スケジューラが内部的にキャッシュドライバを使っている事は分っていたので、変なロックがかかって後続のタスクが実行されていないのでは?
という推測をするも、Redis だとそれは大きな辛みを生む。
(詳しい説明は省略するが、上記のメソッドの挙動を把握していないと、キャッシュドライバでロックがかかってしまう現象は頻発する。
その場合、ロックデータを削除し、再びスケジューラが動く状態にする必要がある。)
AWS で Redis を使う場合、プライベートネットワークに配置するためローカルからはアクセスできず、踏み台サーバを設置してそこから制御する必要がなり、当然 Redis クライアントソフトも必要なる。
また、RDB で select 文を叩くのと同じようなお手軽さで必要な情報を抽出しづらく、問題の原因特定に結構な辛みを生む。
RDB と比較して、「どれが悪さをしているデータなのか」という事が、非常に絞り込みにくい。
「1秒でも早く解決させなければならない」という緊急事態の場合、Redis 丸ごとオールリセットを取る方法が考えられると思うが、そうすると他のユーザが保持していたキャッシュもクリアされるので、出来る限り取りたくない手段となる。
キャッシュドライバを RDB に変えると、スケジューラにて使用しているキャッシュを簡単に絞り込む事が出来ます。
詳細はこちらを。
【Laravel】キャッシュドライバをdatabase にする場合、chache のテーブルは2つ必要
【Laravel】schedule の onOneServer メソッドを使うと、スケジューラが安定しない? キャッシュドライバが原因かもしれません。
何か怪しい所があれば、select 文を叩いて調べ、該当のデータを delete。
RDS なので、トンネルを使えばローカルマシンからでも制御可。
超お手軽。
特に、「AWS環境でしか起こらない問題」については、トレースが非常に難しくなる事が多く、保守容易性の確保は非常に重要な問題となります。
RDB にする事で、速度は Redis と比較すると落ちる事になるかもしれませんが、スケジューラで処理している内容に比べると微々たる量ですし、何より安定性と保守容易性を犠牲にしてまで速度を重視する場面でもなかったので、RDB に切り替えました。
「キャッシュドライバといえば Redis 一択」という考え方もアリなのかもしれませんが、場合によっては非常に大きな辛みを生む事もあるのではないかと思います。
今回は割と特殊なケースなのかもしれませんが、キャッシュドライバに RDB を選択する事は、十分検討の余地があると思います。
というか、今回のプロジェクトでは、再び Redis に切り替えるつもりは無いです。