🤒

# (6)障害検知機能の追加

に公開

Laravel + cron + AWS CloudWatch で実装する障害検知・ジョブ監視設計


以下、githubのソースコードリンクです。これを基に解説していきます。
https://github.com/EggDogg64/ohgiri_for_GitHub


はじめに

この大喜利アプリケーションにおいて、最も重要な機能の一つが
お題のスケジュール管理(Cronjob) です。

Linux の cronjob を使って定期処理を実行していますが、
本番運用を考えると以下のリスクが存在します。

  • cron がエラーで落ちる
  • cron 自体が止まる
  • サーバが落ちる
  • サーバが高負荷で正常に処理できない

本記事では、これらを想定した 多層的な障害検知・監視設計 を紹介します。


監視設計の全体像

本システムでは、以下の 3 レイヤで監視を行います。

① アプリ内監視(Laravel Scheduler)
② cron 自己監視(heartbeat)
③ 外部監視(AWS CloudWatch)
レイヤ 目的
Scheduler ジョブ失敗の即時検知
heartbeat cron 停止の検知
CloudWatch サーバ障害・高負荷検知

新しく追加する機能

● スケジュール監視機能

cron で実行されるジョブが失敗した場合に、管理者へメール通知する。

● サーバ死活監視機能

サーバが停止した場合に、AWS 側からメール通知する。

● CPU 使用率監視機能

直近 5 分間の CPU 使用率が 80% を超えた場合に通知する。

1. スケジュール監視機能(Laravel Scheduler)

Scheduler 設定(routes/console.php)

use Illuminate\Support\Facades\Schedule;

Schedule::command('daily:process')
    ->everyMinute()
    ->emailOutputOnFailure('admin@admin.com');

Schedule::command('odai:process')
    ->dailyAt('12:00')
    ->emailOutputOnFailure('admin@admin.com');

emailOutputOnFailure()Laravel Scheduler 専用のメソッド で、
コマンドが異常終了(exit code ≠ 0)した場合のみ、
標準出力・標準エラーをメール送信します。


ジョブ側の実装(重要)

class DailyProcess extends Command
{
    protected $signature = 'daily:process';

    public function handle(): int
    {
        try {
            // 処理省略
            return Command::SUCCESS;

        } catch (Throwable $e) {
            report($e);
            throw $e; // ← exit code を失敗扱いにするため必須
        }
    }
}

なぜ throw し直すのか?

  • 例外を握りつぶすと exit code = 0 になる
  • emailOutputOnFailure失敗時のみ発火
  • よって 必ず例外を再スローする必要がある

2. cron 自己監視(heartbeat)

heartbeat を更新するジョブ

Schedule::call(function () {
    Cache::put('cron_heartbeat', now());
})->everyMinute();

heartbeat をチェックする監視ジョブ

Schedule::command('cron:check-heartbeat')
    ->everyFiveMinutes()
    ->emailOutputOnFailure('admin@admin.com');
class CheckCronHeartbeat extends Command
{
    protected $signature = 'cron:check-heartbeat';

    public function handle(): int
    {
        try {
            $lastRun = Cache::get('cron_heartbeat');

            if (!$lastRun || now()->diffInMinutes($lastRun) > 5) {
                throw new \RuntimeException('Cron stopped');
            }

            return Command::SUCCESS;

        } catch (Throwable $e) {
            report($e);
            throw $e; // Scheduler failure 扱い
        }
    }
}

これにより、cron が 5 分以上止まった場合にアラートが飛ぶ ようになります。


3. サーバ死活監視・CPU 監視(AWS)

アプリ内の監視だけでは、サーバ自体が落ちた場合に検知できません

そのため、AWS のマネージドサービスを利用します。

使用サービス

  • Amazon CloudWatch:監視・アラーム
  • Amazon SNS:通知(メール)

監視内容

  • EC2 インスタンスの Status Check
  • CPU 使用率(5 分平均 > 80%)

公式ドキュメント


まとめ

  • 監視は一層では足りない
  • アプリ・cron・インフラの 三段構え が重要
  • 「監視が壊れた場合の監視」まで考えると安心

今後は、

  • DB 冗長化
  • ネットワーク構成
  • 障害時の復旧戦略

なども学びつつ、
個人開発での実装で理解を深めていきたいと思います!(^^)

Discussion