トップ / システム / cron 自動実行
cron 自動実行
このページでできること
- cron からクヌギスキーマの自動クロールを走らせる仕組み(
cron/run_cron.php)の動作を把握できます。 - 「1 時間に 1 回 cron を叩き、毎回 N 件ずつ消化する」新仕様の流れを理解できます。
- 1 万 URL 規模のプロダクトでも、1 日に複数回の cron 起動で確実に消化できる設計と、その安全策(トークン保護・URL レベル重複防止)を理解できます。
- cron が動かないときの切り分けポイントがわかります。
エントリポイント: cron/run_cron.php。Web 画面ではなく、サーバの cron や CLI から呼び出します。1 時間に 1 回叩く前提で組まれています。
新仕様の考え方
クヌギスキーマの cron は 「日に何度叩いても、その日にまだ取っていない URL だけを上限件数まで処理する」 設計になっています。これにより、URL 数の多いプロダクトでも 1 回あたりの cron を有限時間で終わらせ、残りは次の毎時起動に持ち越すことができます。
1 万 URL のプロダクトの動作イメージ
- スケジュール: 例えば 1 日と 15 日にチェック、間隔 5 秒、上限 500 URL/cron。
- cron は毎時
0 * * * *で起動。 - 1 日 0:00 に最初の cron が走ると、未クロール 500 URL を処理 → 残り 9,500。
- 以降 1:00、2:00 ... と毎時 500 URL ずつ処理し、約 20 時間で 1 万 URL を消化。
- 翌 1:00 以降の cron は「当日未クロール 0 件」と判定してスキップ。
1 起動の流れ
cron/run_cron.php が起動されると、次の処理が走ります。
- CLI 経由なら無条件で先に進む。Web 経由の場合は
data/cron_secret.txtが存在し、かつ?secret=<値>が一致しないと403 forbiddenで停止。 set_time_limit(0)とignore_user_abort(true)でタイムアウト抑制。- 本日の日付(
YYYY-MM-DD)と日(j= 1〜31)を取得。 Repository::getCronMaxUrlsPerRun()で「この cron 実行で処理する URL 数の上限」を取得(Cron スケジュール 画面で設定。既定 500、0 で無制限)。$remaining変数として保持。Repository::allSchedulesDueToday()で「enabled=1+ 今日の日がdays_jsonに含まれる」プロダクトをproduct_id ASC順に抽出(last_triggered_date による日次ロックは撤廃済み)。- 該当プロダクトを
product_idの小さい順に処理:$remainingが 0 以下になったら「URL 予算を使い切ったので残りプロダクトはスキップ」して終了。Repository::listUrlsNotCrawledOnDate($pid, $today)で「当日まだクロール結果が無い URL」だけを取得(id ASC順)。- 0 件なら「pending なし」としてスキップ(ただし
last_triggered_dateは更新)。 - 1 件以上なら、残り予算分だけ
array_slice()で切り出してCrawler->run($pid, $batch, $delay, 'cron')。 - 消化した件数を
$remainingから引く。 cron_logへ 1 行 INSERT、cron_schedule.last_triggered_dateを本日に更新。
- 最後に「
cron finished: processed=N url(s)」を出力して終了。
「同じ URL が同日に二度走らない」のはなぜ?
旧仕様では
cron_schedule.last_triggered_date によって「1 日 1 プロダクト 1 回」をブロックしていました。新仕様では last_triggered_date によるブロックは外し、代わりに URL 1 件ずつ「crawl_results に当日(JST)の行があるか?」を直接チェックする方式に変わりました。これにより、毎時 cron でも重複は起きません。同時に last_triggered_date は「最後に cron がクロールを動かした日」を示す情報として引き続き更新されます。
CLI からの呼び出し(推奨)
# 毎時 0 分に実行(1 時間に 1 回)
0 * * * * /usr/bin/php /<配置先絶対パス>/cron/run_cron.php >> /<配置先絶対パス>/data/cron.log 2>&1
- 共用レンタルサーバでは、サーバ管理画面の「Cron 設定」から登録するのが手っ取り早いです(Xserver の手順)。
- VPS / 専用サーバでは
crontab -eで直接編集。 - PHP の実行パスは
which phpまたはwhich php8.3等で確認してください。 - 毎時はあくまで一例です。サイトの URL 数 × 1 回あたり上限 × 1 日に流せる時間枠から逆算して、間隔を 30 分(
0,30 * * * *)にする・夜間だけ走らせる(0 1-5 * * *)など、自由に調整してください。
Web 経由での呼び出し(トークン保護必須)
cron デーモンが使えない環境では、外部の死活監視サービスやUptimeRobot のような HTTP 監視ツールから定期的に叩く構成も可能です。ただし必ずトークン保護を有効にしてください。
- サーバ上で十分長いランダム文字列を生成:
openssl rand -hex 32 - その文字列を
data/cron_secret.txtに 1 行で保存(末尾改行はあってもなくても OK)。 - 外部監視から
https://<サーバ>/cron/run_cron.php?secret=<その文字列>を 1 時間に 1 回叩く。 data/cron_secret.txtが存在しない、あるいは?secret=が一致しない場合は403を返します。Basic 認証の認可情報を URL に含められない外部監視サービスでも、この方式なら使えます。
Web 経由での実行に関する注意
- 外部監視からの呼び出し URL(とくに
?secret=)は、HTTPS のクエリ文字列としてプロキシのログに残る可能性があります。可能な限り CLI 経由を選んでください。 - Basic 認証を有効にしている場合、
cron/run_cron.phpも Basic 認証の対象になります。CLI からの実行には影響しませんが、Web 経由で叩く場合は監視ツール側に Basic 認証の資格情報も渡す必要があります。 - 共用サーバの PHP 実行時間制限により、上限を大きくしすぎると HTTP タイムアウトに当たる可能性があります。Cron スケジュール の「1 回あたりの URL 上限」を控えめにし、その代わり cron 頻度(毎時、30 分ごと等)を上げて分散させてください。
cron_log での実行履歴の見方
cron が動いた痕跡は次の 3 か所に残ります。
data/cron.log:>> data/cron.log 2>&1リダイレクト先。cron start: today=YYYY-MM-DD, max_urls_per_run=500、product N (...): pending=X, batch=Y (delay=Zs, remaining_budget=...)、cron finished: processed=N url(s)のような行が時系列で並びます。cron_logテーブル: 各プロダクトの実行サマリー(成功・失敗件数)。SQLite を直接見れば確認可能。crawl_runs+crawl_results: クロール 1 回分の詳細データ。結果一覧 画面で確認できます(最新クロール)。
うまく動かないときのチェックポイント
| 症状 | 対処 |
|---|---|
| cron 時刻になっても何も起きない | data/cron.log にエントリが追記されているか確認。何も無ければ cron 設定そのものが動いていない(パス・PHP のフルパス・cron デーモン稼働を見直す)。 |
| 「no products due today」とログに出る | 本日の日(1〜31)が、どのプロダクトの cron_schedule.days_json にも含まれていない、または enabled=0 状態。Cron スケジュール 画面で見直す。 |
| 毎時走っているのに進まない | cron ログに「pending=0」が並んでいないか確認。当日分は既に消化済みかもしれません(翌実行日まで何も起きないのが正常)。再評価したい場合は 手動でクロール実行 から「全 URL を再クロール」を実行。 |
| 「cron URL budget exhausted」とログに出る | 1 回の上限まで処理した正常終了です。次の毎時起動で続きを処理します。Cron スケジュール の「1 回あたりの URL 上限」を増やすか、cron 頻度を上げることで消化スピードを調整できます。 |
| HTTP 経由で叩いて 403 | data/cron_secret.txt が存在し、内容が ?secret= と一致しているか確認。改行の有無で比較に失敗することがあるので、テキストエディタで末尾改行を整える。 |
関連ページ
実行日と「1 回あたりの URL 上限」の設定は Cron スケジュール、エックスサーバーでの具体的な設定例は インストール方法 → Xserver での Cron 設定例。手動で残りを消化したい場合は 手動でクロール実行。