venetu
Мой дом здесь!
- Регистрация
- 28 Мар 2007
- Сообщения
- 745
- Реакции
- 273
- Автор темы
- #1
Решил, что это достойно отдельной темы.
Самая главная проблема крона - это то, что он может выполняться несколько раз одновременно. В простейшем варианте мы
1) Проверяем, не наступило ли время
2) Если наступило, выполняем нужные действия
3) Записываем куда-то время следующего запуска
При этом, если выполняются два или более экземпляра скрипта, то второй может вклиниться в тот момент, когда первый уже проверил, что пора выполняться, а новое время еще не сохранил - и в результате пойдут выполняться оба. Для эащиты от такого можно использовать семафоры, или транзакции в mysql, но можно попытаться и проще.
И в любом случае, нам придется где-то хранить время следующего запуска.
Вариант для MySQL
Тут мы одним махом проверили время и сразу же его проапдейтили до следующего значения. Встроенный в mysql механизм блокировок гарантирует, что mysql_affected_rows() будет true только у одного экземпляра скрипта. Табличка crontab при этом нужна простейшая, по сути нам надо хранить только DATETIME - время следующего запуска.
Но конечно же дергать мускул ради такой задачи пожалуй слишком расточительно. Так что немного покопавшись с файловыми блокировками сделал вариант с хранением в файле:
Тут по-хорошему файл после записи еще надо транкейтить по новой длине (в нашем случае это не важно, т.к. хранимая в нем дата будет всегда одинаковой длины), анлочить (автоматически анлочится при закрытии хендла) и закрывать (автоматически закрывается при завершении скрипта). Автоматизация рулит.
Самая главная проблема крона - это то, что он может выполняться несколько раз одновременно. В простейшем варианте мы
1) Проверяем, не наступило ли время
2) Если наступило, выполняем нужные действия
3) Записываем куда-то время следующего запуска
При этом, если выполняются два или более экземпляра скрипта, то второй может вклиниться в тот момент, когда первый уже проверил, что пора выполняться, а новое время еще не сохранил - и в результате пойдут выполняться оба. Для эащиты от такого можно использовать семафоры, или транзакции в mysql, но можно попытаться и проще.
И в любом случае, нам придется где-то хранить время следующего запуска.
Вариант для MySQL
PHP:
// id=1 - ежедневно в 00:05
$query = "UPDATE crontab
SET atime = '".date('Y-m-d 00:05:00', time()+24*60*60)."'
WHERE atime < '".date('Y-m-d H:i:s')."' AND id=1 LIMIT 1";
mysql_query($query);
if (mysql_affected_rows()) {
// выполняем крон.
}
Код:
CREATE TABLE crontab (
id tinyint(3) unsigned NOT NULL auto_increment,
atime datetime NOT NULL,
PRIMARY KEY (id)
)
Но конечно же дергать мускул ради такой задачи пожалуй слишком расточительно. Так что немного покопавшись с файловыми блокировками сделал вариант с хранением в файле:
PHP:
$fp = fopen('cron.daily.txt', 'r+');
$atime = strtotime(fread($fp,20));
if ($atime < time() && flock($fp, LOCK_EX + LOCK_NB)) {
fseek($fp,0);
fwrite($fp, date('Y-m-d 00:05:00', time() + 24*60*60));
// выполняем cron
}
Тут по-хорошему файл после записи еще надо транкейтить по новой длине (в нашем случае это не важно, т.к. хранимая в нем дата будет всегда одинаковой длины), анлочить (автоматически анлочится при закрытии хендла) и закрывать (автоматически закрывается при завершении скрипта). Автоматизация рулит.