ホーム › ブログ › PHP・Laravelの保守・バージョンアップ › Laravel の定期処理(cron)とキューが止まったときの確認手順と再発防止

PHP・Laravelの保守・バージョンアップ

Laravel の定期処理(cron)とキューが止まったときの確認手順と再発防止

結論から書くと、Laravel の定期処理やキューが止まったら、「cron が schedule:run を毎分呼べているか」と「キューのワーカーが動き続けているか」を分けて確かめます。どちらもコードの外の仕組みに支えられているので、先にサーバー側を見ます。

この記事では、Laravel のログ全般の読み方と、PHP のバージョンを切り替えて動かなくなったときの切り分けは扱いません。後者は「レンタルサーバーで PHP のバージョンを切り替えたら動かなくなったときの切り分け」で説明しています。

前提: 定期処理とキューは別の仕組みで動く

定期処理(スケジューラ) は、サーバーの cron(決まった時刻にコマンドを動かす仕組み)に1行だけ登録し、schedule:run を毎分実行する仕組みです。

* * * * * cd /path/to/project && /path/to/php artisan schedule:run >> /dev/null 2>&1

処理の定義は、Laravel 10 までの構成では app/Console/Kernel.php、11 以降の構成では routes/console.php(bootstrap/app.php の withSchedule のことも)にあります。

キュー は、メール送信など時間のかかる処理(ジョブ)をデータベースなどに積み、queue:work で起動したワーカーが取り出して処理する仕組みです。ワーカーは常に動かしておくプロセスで、公式は Supervisor(止まったプロセスを起動し直すソフトウェア)などを使うよう案内しています。

症状 疑うもの
集計やバッチの結果が出ない スケジューラ(cron)
操作の後のメールが届かない ワーカー
両方とも止まっている メンテナンスモード(php artisan down でサイトを止めている間は、定期処理もジョブも動かない)、移転や再起動の後の cron・ワーカーの設定漏れ

コマンドは 13.x のドキュメントに沿っています。古い版では、その版のドキュメントで確かめます。

定期処理(スケジューラ)の確認手順

  1. cron の登録。 crontab -l で上の1行があるかを見ます。管理画面で登録するサーバーもあるので、契約しているサーバーのマニュアルで確認します。
  2. 実行ユーザーと PHP のパス。 cron は登録したユーザーで動くので、Web サーバーと別のユーザーだとログやキャッシュを書き込めないことがあります。cron の行には PHP をフルパスで書き、/path/to/php -v で Web と同じバージョンかを確かめます(which php の結果は cron の環境と違うことがあります)。
  3. Laravel から見えているか。 php artisan schedule:list で、登録された処理と次の実行時刻を一覧にできます。
  4. 手で動かす。 cron と同じユーザーで、止まっている処理を直接実行し、出力を見ます(cron の行の >> /dev/null 2>&1 は出力を捨てます)。メール送信や更新を伴う処理は本番で実際に動くので、二重に実行されないか確かめてから動かします。

重複防止のロック。 withoutOverlapping() を付けた処理は、前回が終わるまで次を始めません。途中でサーバーが止まるとこのロックが残り、既定の24時間が過ぎるまで、その処理だけ動きません。ロックは schedule:clear-cache で消せます。

キューの確認手順

  1. 接続の設定。 .env の QUEUE_CONNECTION(無ければ config/queue.php の default)が sync ならジョブはその場で処理され、null なら捨てられ、database や redis ならワーカーが要ります。config:cache で設定をキャッシュしていると .env は読み込まれないので、直したらキャッシュを作り直し、ワーカーも起動し直します。
  2. ワーカーが動いているか。 プロセスの一覧(ps aux | grep "queue:work")を見ます。database ドライバーなら、jobs テーブルの件数が増え続けていないかも見ます。ワーカーはタイムアウトや queue:restart でも終了するので、起動し直す仕組み(Supervisor の設定など)があるかも確かめます。
  3. 失敗したジョブ。 決めた回数を超えて失敗したジョブは failed_jobs テーブルに入り、queue:failed で一覧にできます。原因を直したらワーカーを起動し直し(後述)、queue:retry で再実行します。同じ処理がもう一度走るので、メールの二重送信などに注意します。

コードを更新した後。 ワーカーはコードの更新に気づかないので、デプロイ(新しいコードを本番に反映する作業)の手順に php artisan queue:restart を入れます。これはワーカーを終了させるだけで、起動し直すのは Supervisor などの役目です。

常駐プロセスを置けないサーバーでの選択肢

ワーカーを毎分起動し、空になったら終わらせる。 ジョブを処理し終えたら終了する --stop-when-empty 付きのワーカーを、スケジューラで毎分起動します。withoutOverlapping() で重ねて起動せず、ほかの定期処理を待たせないよう runInBackground() で裏で動かします。長く動くプロセスが許されているかは、契約しているサーバーのマニュアルで確認します。

// routes/console.php(11 以降)の例。Kernel.php では $schedule->command(...) と書く
Schedule::command('queue:work --stop-when-empty')
    ->everyMinute()
    ->withoutOverlapping()
    ->runInBackground();

ジョブは次の起動まで待つので、急ぐ処理には向きません。ワーカーが強制終了されると上のロックが残り、既定では24時間、次のワーカーが起動しません。withoutOverlapping() に分数を渡すと、この期限を短くできます。

ワーカー無しで処理する。 sync 接続はその場で処理するため画面の応答が待たされ、失敗は failed_jobs に残りません(公式では開発やテスト向け)。Laravel 12 以降のドキュメントにある deferred・background 接続は、応答を返した後に処理します。

再発を防ぐ: 失敗を知らせ、止まったことに気づく

失敗は、スケジューラの onFailure() やジョブの failed メソッドで通知できます。ただ、cron が消えた、ワーカーが落ちたといった停止には気づけないので、次も用意します。

  • スケジューラの停止に気づく。 pingOnSuccess() で処理が成功したときに指定の URL へアクセスさせ、決まった時刻までにアクセスが無ければ知らせる外部の監視と組み合わせます。cron ごと止まっても気づけます。
  • キューの滞留に気づく。 queue:monitor database:default --max=100 のようにスケジューラで毎分実行すると、件数が --max を超えたときに QueueBusy イベントが発生します。通知を送る処理は、このイベントを受けて別に書きます。

h-system でできること

h-system では、他社や前任者が作った PHP・Laravel のシステムについて、定期処理やキューが止まるなどの不具合の調査と修正を、開発者本人が直接お引き受けしています。現状を確かめる調査だけのご依頼も可能です。初回のご相談と概算のお見積りは無料で、詳細な調査は有償です。範囲と費用は着手前にご案内します。

TOP