Запуск PHP-приложения в Windows-daemon или cron?

Мне нужен совет по реализации. У меня есть MySQL DB, который будет написан удаленно для задач для обработки локально, и мне нужно мое приложение, написанное на PHP, чтобы выполнить эти задачи imediatly по мере их поступления.

но, конечно, мое приложение PHP должно быть сказано, когда запускать. Я думал об использовании заданий cron, но мое приложение находится на машине windows. Во-вторых, мне нужно постоянно проверять каждые несколько секунд, а cron может делать только каждую минуту.

Я подумал написание демона PHP, но я получаю согласие на то, как он будет работать, и если это даже хорошая идея!

Я был бы признателен за любые советы о лучшем способе сделать это.

8 ответов


pyCron является хорошей альтернативой CRON для Windows:

pyCron

поскольку эта задача довольно проста, я бы просто настроил pyCron для запуска следующего сценария каждую минуту:

set_time_limit(60); // one minute, same as CRON ;)
ignore_user_abort(false); // you might wanna set this to true

while (true)
{
    $jobs = getPendingJobs();

    if ((is_array($jobs) === true) && (count($jobs) > 0))
    {
        foreach ($jobs as $job)
        {
            if (executeJob($job) === true)
            {
                markCompleted($job);
            }
        }
    }

    sleep(1); // avoid eating unnecessary CPU cycles
}

таким образом, если компьютер пойдет вниз, у вас будет задержка в худшем случае 60 секунд.

вы также можете посмотреть семафоры или какую-то стратегию блокировки, например, использовать переменную APC или проверить наличие файла блокировки на избегайте условий гонки, используя APC, например:

set_time_limit(60); // one minute, same as CRON ;)
ignore_user_abort(false); // you might wanna set this to true

if (apc_exists('lock') === false) // not locked
{
    apc_add('lock', true, 60); // lock with a ttl of 60 secs, same as set_time_limit

    while (true)
    {
        $jobs = getPendingJobs();

        if ((is_array($jobs) === true) && (count($jobs) > 0))
        {
            foreach ($jobs as $job)
            {
                if (executeJob($job) === true)
                {
                    markCompleted($job);
                }
            }
        }

        sleep(1); // avoid eating unnecessary CPU cycles
    }
}

Если вы придерживаетесь демона PHP, сделайте себе одолжение и отбросьте эту идею, вместо этого используйте Gearman.

редактировать: однажды я задал связанный с этим вопрос, который может вас заинтересовать:Анатомия распределенной системы в PHP.


Я предложу что-то необычное: вы сказали, что вам нужно запустить задачу в точке, где данные записываются в MySQL. Это означает, что MySQL "знает", что что-то должно быть выполнено. Это звучит как идеальный сценарий для UDF MySQL sys_exec.

в принципе, было бы неплохо, если бы MySQL мог вызвать внешнюю программу, как только что-то случилось с ней. Если вы используете упомянутый UDF, вы можете выполнить PHP-скрипт изнутри-скажем, вставить или обновить триггер. На с другой стороны, вы можете сделать его более удобным для ресурсов и создать событие MySQL (предполагая, что вы используете соответствующую версию), которое будет использовать sys_exec для вызова PHP-скрипта, который делает определенные обновления через предопределенные интервалы - что уменьшает потребность в Cron или любой подобной программе, которая может выполнить что-то через предопределенные интервалы.


Я бы определенно не советовал использовать cronjobs для этого.

cronjobs-хорошая вещь, очень полезная и легкая для многих целей, но, как вы описываете свои потребности, я думаю, что они могут вызвать больше осложнений, чем они делают хорошо. вот некоторые вещи, чтобы рассмотреть:

  • что произойдет, если рабочие места пересекаются? выполнение занимает больше времени, чем одна минута? есть ли общие ресурсы/взаимоблокировки/tempfiles? - наиболее распространенным методом является использование файла блокировки, и остановите выполнение, если оно занято прямо в начале программы. но программа также должна искать дополнительные задания прямо перед ее завершением. - это, однако, также может усложниться на машинах windows, потому что они AFAIK не поддерживают блокировки записи из коробки

  • cronjobs-это боль в заднице для поддержания. если вы хотите контролировать их, вам нужно реализовать дополнительную логику, такую как проверка при последнем запуске программы. однако это может быть сложно, если ваша программа должен работать только по требованию. лучшим способом было бы какое-то поле" задание завершено " в базе данных или удалить обработанные строки.

  • в большинстве unix-систем cronjobs сейчас довольно стабильны, но есть много ситуаций, где вы можете сломать свою систему cronjob. большинство из них основано на человеческом заблуждении. например, системный администратор, не выходящий из редактора crontab должным образом в режиме редактирования, может вызвать удаление всех cronjobs. многие компании также не имеют надлежащая система мониторинга по вышеуказанным причинам и уведомление, как только их услуги испытывают проблемы. на этом этапе часто никто не записал / не поставил под контроль версии, какие cronjobs должны работать и начинаются дикие догадки и работы по реконструкции.

  • cronjob maintaince может быть еще сложнее, когда используются внешние инструменты и среда не является родной системой unix. сисадмины должны получить знания о большем количестве программ, и они могут иметь потенциал ошибки.

Я честно думаю, что просто небольшой скрипт, который вы запускаете с консоли и открываете, просто отлично.

<?php
while(true) {
 $job = fetch_from_db();
 if(!$job) { 
    sleep(10) 
 } else {
    $job->process();
 }
}

вы также можете коснуться файла (изменить временную метку модификации) в каждом цикле, и вы можете написать сценарий nagios, который проверяет, что эта временная метка устарела, чтобы вы знали, что ваша работа все еще работает...

Если вы хотите, чтобы он запускался с системой, я рекомендую deamon.

PS: в компании я работаю есть большое фоновой активности на нашем сайте (ползание, процессы обновления, расчеты и т. д...) и cronjobs были настоящим беспорядком,когда я начал там. их распределяли по разным серверам, отвечающим за разные задачи. доступ к базам данных осуществлялся через интернет. тонна NFS filesytems, акций samba и т. д. были на месте, чтобы поделиться ресурсами. место было полно единичных точек сбоев, узких мест и что-то постоянно ломалось. их было так много технологии включали в себя то, что было очень трудно поддерживать, и когда что-то не работало, требовались часы отслеживания проблемы и еще час того, что эта часть даже должна была делать.

теперь у нас есть единая программа обновления, которая отвечает буквально за все, он работает на нескольких серверах и у них есть конфигурационный файл, который определяет задания для выполнения. eveyrthing отправляется от одного родительского процесса, выполняющего бесконечный цикл. его легко контролировать, customice, synchronice и все работает гладко. это избыточно, это syncrhonized и гранулярность в порядке. так он работает параллельно и мы можем масштабировать до столько серверов, сколько нам нравится.

Я действительно предлагаю сесть на достаточное время и подумать обо всем в целом и получить картину всей системы. затем инвестируйте время и усилия, чтобы реализовать решение, которое будет отлично служить в будущем и не распространяет тонны различных программ по всему вашему система.

pps:

Я много читал о минимальном interaval 1/5 минут для cronjobs / задач. вы можете легко обойти это с помощью произвольного скрипта, который занимает этот интервал:

// run every 5 minutes = 300 secs
// desired interval: 30 secs
$runs = 300/30; // be aware that the parent interval needs to be a multiple of the desired interval
for($i=0;$i<$runs;$i++) {
 $start = time();
 system('myscript.php');
 sleep(300/10-time()+$start); // compensate the time that the script needed to run. be aware that you have to implement some logic to deal with cases where the script takes longer to run than your interavl - technique and problem described above
}

Это похоже на работу для сервера заданий;) посмотрите на Gearman. Дополнительным преимуществом такого подхода является то, что он запускается удаленной стороной, когда и только тогда есть что делать, а не опрос. Особенно в интервалах меньше, чем (скажем) 5 мин опрос уже не очень эффективен, в зависимости от задач, которые выполняет задание.


быстрый и грязный способ-это создать цикл, который постоянно проверяет, есть ли новая работа.

Psuedo-code

set_ini("max_execution_time", "3600000000"); 
$keeplooping = true;
while($keeplooping){

   if(check_for_work()){
      process_work();
   }
   else{
     sleep(5);
   }

   // some way to change $keeplooping to false
   // you don't want to just kill the process, because it might still be doing something
}

вы пробовали планировщик windows (поставляется с Windows по умолчанию)? В этом вам нужно будет указать путь php и путь к файлу php. Он хорошо работает


не можете ли вы просто написать программу java / C++, которая будет запрашивать вас через заданный интервал времени? Вы можете включить это в список программ запуска, чтобы он всегда работал. Как только задача найдена, она может обрабатывать ее в отдельном потоке и обрабатывать больше запросов и отмечать другие завершенные.


самый простой способ-использовать embed Windows schedule.

запустите скрипт с помощью php-cli.exe с заполненным php.ini с расширения вашего сценария.

но я должен сказать, что на практике вам не нужен такой короткий промежуток времени для выполнения запланированных заданий. Просто сделайте несколько тестов, чтобы получить лучшее значение интервала времени для вашего. Не рекомендуется устанавливать интервал времени менее 1 минуты.

и еще один маленький совет: сделайте некоторый файл блокировки на начало вашего скрипта (функция PHP flock), проверьте наличие возможности записи в этот файл блокировки, чтобы предотвратить работу двух или более копий одновременно и в конце вашего скрипта разблокируйте его после разблокировки.

Если вам нужно записать результат вывода в БД, попробуйте использовать триггеры MySQL вместо PHP. Или используйте события в MySQL.