Cronの多重起動を防止する

PHPでDM配信システムを実装した。

仕組みは以下。

  • メールの件名、本文、配信先をDBに登録
  • Cronで5分間隔でmail_send.phpを実行。
  • mail_send.php 内でDBから配信済みフラグが0のレコードを70件取得し、メール配信
  • 配信が完了した宛先には配信済みフラグを1に変更
  • 以後繰り返し。

詳しい実装方法はまた別の記事で紹介するかも。

んで、Cronはこんな感じ

*/5 * * * * php /path/to/dir/mail_send.php

これはこれでうまく動くんだけど、なんらかの問題があって全てを配信できなかった場合、前回配信が終わらず配信フラグが0の配信先を再度取得してしまう。 結果、同じ配信先に2通のメールが配信されてしまうことになる。 これはまずい。

lockfileを作成して多重起動を防止

やり方は結構簡単で、Cronを実行した際に、lockfileを作成し、処理が全て終わったらlockfileを削除する。 Cronが回ってきた時、lockfileが存在する(処理が完了していない)場合は処理を実行しない。

コードはこんな感じ。

// 同階層にlockfileを作成する場合、__DIR__ . '/lockFile.txt';でもおk。
$lockFile = '/path/to/dir/lockFile.txt';

if (file_exists($lockFile)) {
  exit(0); // ファイルが存在する場合、プログラムを停止させる
}

// 実行する前にファイルを作成する
touch($lockFile);

****************************************************
メール配信処理
****************************************************

///処理が終わったらlockfifleを削除する
unlink($lockFile);

やってみると多重起動は防止できていることがわかると思うる。

念の為、自動でlockfileを削除する処理を追加する

万が一lockfileの削除ができなかった場合、処理が終わってないと判断され、手動でlockfileを削除しない限りメール配信がされないことになってしまう。

そこで、作成から一定時間経過したlockfileは削除するという処理を追加する。

// 同階層にlockfileを作成する場合、__DIR__ . '/lockFile.txt';でもおk。
$lockFile = '/path/to/dir/lockFile.txt';

// 作成時間から5分経過していたらlockfileを削除する
$limit = 5;
if (strtotime(date('Y-m-d H:i:s')) - filemtime($lockFile) / 60 > $limit) {
  unlink($lockFile);
}

if (file_exists($lockFile)) {
  exit(0); // ファイルが存在する場合、プログラムを停止させる
}

// 実行する前にファイルを作成する
touch($lockFile);

****************************************************
メール配信処理
****************************************************

///処理が終わったらlockfifleを削除する
unlink($lockFile);

これでCronの多重起動が防止できました。

よかったら参考にしてみてください。