Как реализовать повторяющиеся задачи в php (cron)?
Здравствуйте! Направьте, пожалуйста, в правильное русло.
Есть 2 ситуации, которые необходимо решить с использованием php.
1. Воспроизведение функции в четко определенное время. Наглядный пример - пользователь создает напоминание на определенную дату и время (например, на сегодня, 22:35) и ровно в это время должен отработать скрипт (в данном случае, к примеру, отправить уведомление на почту).
Как реализовать это наиболее грамотно? Настроить по cron с промежутком в 1 минуту скрипт, который будет проверять наличие каких-либо заданий на текущую минуту? Это будет наиболее верным решением? Как быть, если выполнение функции требует времени (к примеру, речь о парсинге), и в определенное время нужно выполнить несколько заданий одновременно? К примеру, критически важно спарсить данные из трех источников минуту в минуту.
Я говорю о том, что если реализовать это в порядке очереди, то следующая итерация функции произойдет только после окончания предыдущей. Т.е. пока скрипт не спарсит первые данные, к парсингу вторых он не перейдет.
Читал о многопоточности в curl, т.е. на случай парсинга решение есть, но как быть в других ситуациях?
2. Реализация повторения функции. Пример - пользователь запускает задание, в рамках которого одна и та же функция должна выполниться на сервере, например, 100 раз с интервалом в 40 секунд. Как это реализовать наиболее грамотно?
Основная проблема тут именно во времени выполнения скрипта. Я знаю про set_time_limit / max_execution_time, но единственное ли это решение? И вообще насколько правильно, например, отключать максимальное время выполнения скрипта, если мы не знаем, сколько это может занять времени?
Вопросы скорее не о конкретных примерах, т.е. функция может быть любой - отправка почты, обращение к api, парсинг данных и проч. Интересно именно то, как правильно это реализовать. Подскажите, куда рыть, что читать.
Есть реализации крона (не сам по себе crontab, а на баше том же) и раз в секунду, можно нагуглить варианты.
Можно использовать сервер очередей (к примеру Gearman). Сервер выполняет задачу и имеет о ней все данные. Задачу можно перепоставить себе же автоматически после выполнения, попутно изменив у нее определенные данные.
Спарсить 3 задачи - тоже легко. Делаются для этого же сервера 3 воркера, которые работают параллельно. Как только гирману поступает задача, свободный воркер её сразу хватает. Поступят 3 задачи - 3 воркера их расхватают и будут выполнять одновременно. Причем для задач можно выставить приоритеты. Необязательные пускать с low, обязательные с high приоритетом. Свободный воркер решит какую задачу брать сам.
Вообще промежуточные данные при запуске скрипта (таймауты и прочее) можно хранить любым nosql решением. Хоть в файл пишите, хоть в redis, хоть в memcache, если обращение к базе некритично. Статусы завершенности задач, типы задач, задачи, которые исполняются - все там же. Ну или опять же в базе. Тут как удобнее.
Раньше, к примеру, мы постраничный парсинг реализовывали через redis. Крон запускался раз в 10 минут (долго парсилось), и в редис клалось значение текущей страницы. При последующем запуске скрипта значение доставалось и по нему отлистывалась следующая страница при запросе к API. Потом этот ключ грохали (уже не вспомню, либо вручную либо по expire) и все начиналось заново.
Я бы делал небольшого отдельного демона/скрипт/whatever, который стартует из-под крона с какой-то частотой, проверяет блокировку (flock-ом, на крайняк), лезет в базу, понимает, какие ему сейчас надо выполнить задачки, запускает child-процессы для их обработки (тут можно и аппетиты ограничить, если надо), отмечает в базе, что процессы запущены, освобождает блокировку и мрёт. Это если погрешность в одну минуту - не смущает.
Если смущает - отдельный демон, который слушает, например, сигналы ОС, и по прибытию сигнала от php-приложения или своего собственного аларма, проделывает вот это всё из первого абзаца, только сперва отключив обработку сигналов ;). При стартек демон пишет свой pid куда-нибудь, чтобы ваше приложение знало, кому сигналить. ;)