26.

Linux cron バッチ実行入門(書式・MAILTO・ログ・systemd timer・Laravel Scheduler)

編集
この記事の要点
  • cron は Linux/Unix の定期実行デーモン。crontab -e で編集
  • 書式は 分 時 日 月 曜日 コマンド。例: 0 3 * * * /usr/bin/php /var/www/run.php(毎日 3 時)
  • 通知無効化は MAILTO=""、ログ出力は >> /var/log/myapp.log 2>&1
  • リトライ・複雑制御はシェルスクリプトでラップ。systemd timer は細かい依存・ログ管理に強い
  • Laravel は * * * * * php artisan schedule:run を 1 つだけ登録し、app/Console/Kernel.php で全タスク管理

cron とは

cron は Linux/Unix の定期実行デーモンです。「毎日 3 時にバックアップ」「5 分毎に死活監視」など、時間トリガで動かしたいバッチを登録します。crontab(cron table)と呼ばれる設定ファイルを crontab -e で編集すると、cron デーモンが自動的に読み直してくれます。

crontab の基本操作

# 編集($EDITOR で開く。初回は vi が多い)
crontab -e

# 内容表示
crontab -l

# 一括削除
crontab -r

# 別ユーザ(root が他人の crontab を編集)
sudo crontab -u www-data -e

書式: 5 フィールド + コマンド

# ┌───── 分 (0-59)
# │ ┌─── 時 (0-23)
# │ │ ┌─ 日 (1-31)
# │ │ │ ┌ 月 (1-12)
# │ │ │ │ ┌ 曜日 (0-7, 0と7が日曜)
# │ │ │ │ │
# * * * * * コマンド

# 毎日 3 時 0 分
0 3 * * * /usr/bin/php /var/www/cleanup.php

# 5 分毎
*/5 * * * * /home/app/healthcheck.sh

# 毎時 0 分・30 分
0,30 * * * * /home/app/sync.sh

# 平日 9-18 時、1 時間毎
0 9-18 * * 1-5 /home/app/business.sh

# 毎月 1 日の 0:00
0 0 1 * * /home/app/monthly_report.sh

# 日曜深夜 1:30
30 1 * * 0 /home/app/weekly_backup.sh

# 特別表記
@reboot     /home/app/startup.sh        # 起動時 1 回
@daily      /home/app/daily.sh          # 0 0 * * * と同じ
@hourly     /home/app/hourly.sh         # 0 * * * * と同じ

cron の落とし穴: 環境変数と PATH

cron はログイン時とは別の最小限の環境で動きます。.bashrc も読まれません:

# ❌ よくあるミス
# シェルで動くのに cron だと「command not found」
* * * * * php /var/www/run.php

# ✅ 修正1: フルパス指定
* * * * * /usr/bin/php /var/www/run.php

# ✅ 修正2: PATH を crontab 冒頭で指定
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
* * * * * php /var/www/run.php

# 環境変数の設定
SHELL=/bin/bash
HOME=/home/app
LANG=ja_JP.UTF-8
MAILTO=""

* * * * * /home/app/run.sh

ログ出力と通知

# 通常: cron は stdout / stderr をユーザにメール送信
# MAILTO="" でメール無効化(推奨)

MAILTO=""

# 標準出力とエラー両方をログへ
0 3 * * * /usr/bin/php /var/www/run.php >> /var/log/myapp.log 2>&1

# 標準出力は捨て、エラーだけログ
0 3 * * * /usr/bin/php /var/www/run.php > /dev/null 2>> /var/log/myapp.err

# 全部捨てる(非推奨)
0 3 * * * /usr/bin/php /var/www/run.php > /dev/null 2>&1

# エラー時だけメール送信したい場合は MAILTO 指定
MAILTO=alerts@example.com
0 3 * * * /usr/bin/php /var/www/run.php > /dev/null
# → 終了コード非 0 or stderr 出力でメール

シェルスクリプトでラップ(推奨)

crontab に直接コマンドを書くより、シェルスクリプトでラップする方がログ・リトライ・通知を管理しやすい:

#!/bin/bash
# /home/app/jobs/daily_report.sh
set -euo pipefail

LOG=/var/log/myapp/daily_report_$(date +%Y%m%d).log
exec >> "$LOG" 2>&1   # 以後の出力は全てログへ

echo "=== START $(date) ==="

cd /var/www/myapp

# リトライ 3 回
for i in 1 2 3; do
    if /usr/bin/php artisan reports:daily; then
        echo "Success on attempt $i"
        break
    fi
    echo "Failed attempt $i, retrying..."
    sleep 30
done

# 失敗時の Slack 通知
if [ $? -ne 0 ]; then
    curl -X POST -H 'Content-type: application/json' \
        --data '{"text":"Daily report failed"}' \
        "$SLACK_WEBHOOK_URL"
fi

echo "=== END $(date) ==="
# crontab
MAILTO=""
0 6 * * * /home/app/jobs/daily_report.sh

多重起動防止: flock

cron は前回が動いていても容赦なく次を起動します。重複防止には flock:

# 同時実行を 1 つだけに(既に動いてたらスキップ)
*/5 * * * * /usr/bin/flock -n /tmp/myjob.lock /home/app/sync.sh

# 既に動いてたら待つ
*/5 * * * * /usr/bin/flock /tmp/myjob.lock /home/app/sync.sh

systemd timer との比較

項目cronsystemd timer
歴史1970 年代から2010 年代から
書式1 行2 ファイル(.timer / .service)
ログ自前で >> logjournalctl で自動収集
依存・順序難しいAfter= / Requires= で表現
遅延起動不可RandomizedDelaySec あり
停止後の再実行不可Persistent=true で実行漏れリカバリ
学習コスト

Laravel Scheduler との連携

Laravel はアプリ内で全タスクを管理し、cron に登録するのは1 行だけ:

# crontab -e(www-data 等のアプリユーザで)
* * * * * cd /var/www/myapp && php artisan schedule:run >> /dev/null 2>&1
// app/Console/Kernel.php
protected function schedule(Schedule $schedule)
{
    // 毎日 3 時
    $schedule->command('cleanup:expired')
        ->dailyAt('03:00')
        ->withoutOverlapping()
        ->appendOutputTo(storage_path('logs/cleanup.log'));

    // 5 分毎
    $schedule->command('queue:work --stop-when-empty')
        ->everyFiveMinutes()
        ->onOneServer();

    // 平日 9-18 時の 1 時間毎
    $schedule->call(fn () => Cache::flush())
        ->hourly()
        ->between('9:00', '18:00')
        ->weekdays();
}

FAQ

Q: 設定したのに動かない
A: ① cron デーモン稼働確認 systemctl status cron(Debian 系)/crond(RHEL 系)、② /var/log/syslog または /var/log/cron、③ コマンドのフルパス・PATH、④ 実行権限 chmod +x

Q: 数秒単位で動かしたい
A: cron の最小単位は 1 分。* * * * * sleep 30 && /path/to/job のような小細工か、systemd timerOnUnitActiveSec=10sec、または常駐デーモン化を検討。

Q: タイムゾーンを変えたい
A: 各エントリの先頭で CRON_TZ=Asia/Tokyo(cron 実装による)。OS タイムゾーンを timedatectl set-timezone Asia/Tokyo で変える方が確実。

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. 環境構築とプロジェクト/アプリの作成
  2. MVC(MVT)のそれぞれの使い方と説明
  3. データベースへの接続と操作
  4. Django Administration
  5. git管理
  6. エラー一覧
  7. バージョンの確認方法
  8. ログ出力方法
  9. SQLのログ出力方法
  10. ログのローテート設定
  11. settings.pyの定数にアクセスする方法
  12. 本番環境へのインストールとアプリのデプロイ(apache編)
  13. 本番環境へのインストールとアプリのデプロイ(nginx編)
  14. djangoアプリの本番の開始URLを変更する
  15. 静的(static)ファイルの置き場所と読み込み(画像、css、js )
  16. CSRFトークンをAjaxで使用する方法
  17. ajaxの使用例(POST編)
  18. ファイルのアップロードとファイルの名前
  19. クイックスタート/チュートリアル
  20. ログイン機能
  21. テンプレート側のログイン判定
  22. ビュー側のログイン判定
  23. 管理者ユーザーの作成/判定と管理画面
  24. モデルのjson化とレスポンス
  25. runserverでポートを指定する方法
  26. cronによるバッチ実行
  27. テンプレートで利用する共通のcontextを定義する方法
  28. プログラムが本番サーバーで反映されない場合の対処法
  29. APIの作成
  30. cron用コマンド・ファイルの作成