読者です 読者をやめる 読者になる 読者になる

PHPでcrontabを意図通り書けているか確認するテストを書く

以下の環境と状況を前提にします

  • あるリポジトリにcrontabに設定したい内容をtxtファイル( cron.txt)を含めてコミットしている
  • コミットされたファイルがデプロイされるとその内容に基づいてデプロイ先サーバーでcrontabが設定される

よくある構成かと思います。
ここでコミットされているファイルに以下のような記述がありました。

* 13 * * * php hoge.php

この設定を書いた意図は、「毎日13時に hoge.phpを起動したい」でした。
しかし実際の挙動は「毎日13時台に毎分 hoge.phpが起動する」になります。

これに気づかないままコミットしてデプロイされてしまうと、本番サーバーに異常な負荷がかかったり、データ不整合が起こる可能性があります。

このリスクを少しだけ減らすためのテストを書きました。

php_cron_test

cron-expressionというパーサーがあったのでこれを用いています。
便宜的に $PROJECT_ROOT/cron_file 配下に cron.txt(群)がある想定とします。
その上でcron.txt内のcrontabの宣言の次に以下の2行を追加します。

  • ###prev YYYY-MM-DD HH:ii:ss
  • ###next YYYY-MM-DD HH:ii:ss

まず、「cron宣言の後にこの2行がないと落ちる」テスト項目が書かれています。
なので、ファイル内のすべてのcron宣言の後に2行追加する必要があります。
追加した2行には「2015年1月1日 0時0分0秒」から見て、

  • prev : 最も直前にcronが動いた時間
  • next : 最も直近でcronが動く予定の時間

を書きます。前述のパターンの場合だと、こんな感じです。

* 13 * * * php hoge.php
###prev 2014-12-31 13:00:00
###next 2015-01-01 13:00:00

つまり、「メモ書きを追加することで『設定した時間が意図通りか』をある程度まで自己確認すること」を目的としたテストです。
実際に、prevの設定値を「2014-12-31 13:59:00」にするか、
cronの宣言を「0 13 * * * php hoge.php」にしないとテストが落ちます。

試しに作ってみた系なので、色々問題はあるかと思っています。

  • cron.txtが汚れる
    • 嫌がる人は嫌がる
  • 意図とはズレていても結果的に期待値が同じprevとnext指定になるケースもきっとある
    • cron-expressionが指定時間からの前後時間を返すメソッドを用意してるためそれに合わせた仕様にしたのでこれは許容
  • 基準日だったり、パース用のprefixは割と適当
    • なので変更してもらって構わない

PerlだとTest::Crontab::Formatがあり、 これはcron.txtに余計な記述をすることなくcrontabのformatをチェックできるので便利です。
最初はこれっぽいものを探していたのですが、見つからなかったのと今回遭遇したケースは 「意図と違う時間の設定 = うっかりミス」だったので、こういうアプローチにしてみました。