Запуск приложения PHP на windows - демон или cron? - PullRequest
6 голосов
/ 22 апреля 2011

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

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

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

Буду признателен за любой совет, как лучше всего это сделать.

Ответы [ 8 ]

8 голосов
/ 28 апреля 2011

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 .

3 голосов
/ 28 апреля 2011

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

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

2 голосов
/ 30 апреля 2011

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

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

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

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

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

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

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

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

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

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

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

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

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

pps:

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

// 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
}
1 голос
/ 22 апреля 2011

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

0 голосов
/ 05 мая 2011

Самый простой способ - это использовать встроенное расписание Windows.

Запустить ваш скрипт с php-cli.exe с заполненным php.ini с расширениями, которые нужны вашему скрипту.

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

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

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

0 голосов
/ 05 мая 2011

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

0 голосов
/ 02 мая 2011

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

0 голосов
/ 22 апреля 2011

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

псевдопользователей-код

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
}
...