Мне нужны рекомендации по внедрению. У меня есть база данных MYSQL, которая будет записываться удаленно для задач, которые будут обрабатываться локально, и мне нужно мое приложение, написанное на PHP, для выполнения этих задач imediatly по мере их поступления.
Но, конечно, мое PHP-приложение должно быть сказано, когда нужно запускать. Я думал об использовании заданий cron, но мое приложение находится на машине с Windows. Во-вторых, мне нужно постоянно проверять каждые несколько секунд, и cron может делать только каждую минуту.
Я думал о написании PHP-демона, но меня приглашают на работу, и если это даже хорошая идея!
Я был бы признателен за любые советы о том, как это сделать.
pyCron – хорошая альтернатива CRON для Windows:
Поскольку эта задача довольно проста, я бы просто setup 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.
EDIT : Я задал соответствующий вопрос, который может вас заинтересовать: Анатомия распределенной системы в PHP .
Я предлагаю вам что-то необычное: вы сказали, что вам нужно запустить задачу в тот момент, когда данные будут записаны в MySQL. Это означает, что MySQL «знает» что-то должно быть выполнено. Это звучит как идеальный сценарий для UDF MySQL sys_exec .
В принципе, было бы неплохо, если бы MySQL мог вызвать внешнюю программу, как только что-то случилось с ней. Если вы используете упомянутый UDF, вы можете выполнить скрипт php изнутри – допустим, триггер INSERT или UPDATE. С другой стороны, вы можете сделать его более дружественным к ресурсам и создать событие MySQL (при условии, что вы используете соответствующую версию), который будет использовать sys_exec для вызова PHP-скрипта, который выполняет определенные обновления через предопределенные интервалы времени, что уменьшает потребность в Cron или любая аналогичная программа, которая может выполнять что-либо с предопределенных интервалов.
я бы определенно не советовал использовать cronjobs для этого.
cronjobs – это хорошо и очень полезно и легко для многих целей, но, поскольку вы описываете свои потребности, я думаю, что они могут создавать больше осложнений, чем они делают хорошо. вот некоторые вещи, которые следует учитывать:
что произойдет, если рабочие места перекрываются? выполнение занимает больше времени, чем одна минута? существуют ли общие ресурсы / блокировки / временные файлы? – наиболее распространенным методом является использование файла блокировки и прекращение выполнения, если оно занято в самом начале программы. но программа также должна искать дополнительные задания непосредственно перед ее завершением. – это, однако, может также усложниться на машинах Windows, потому что они AFAIK не поддерживают блокировки записи из коробки
cronjobs – это боль в заднице для поддержания. если вы хотите их контролировать, вам нужно реализовать дополнительную логику, например, проверку, когда последняя программа запускалась. это может затрудниться, если ваша программа должна работать только по требованию. лучший способ – это какое-то «заполнение задания» в базе данных или удаление строк, которые были обработаны.
на большинстве систем на основе unix cronjobs довольно стабильны сейчас, но есть много ситуаций, где вы можете разбить свою систему cronjob. большинство из них основано на человеческой ошибке. например, sysadmin, не выходящий из редактора crontab, в правильном режиме, может привести к удалению всех cronjob. многие компании также не имеют надлежащей системы мониторинга по указанным выше причинам и уведомляют, как только их службы испытывают проблемы. на данный момент часто никто не записал / поставил под контроль версий, который должен запускаться cronjobs, и начинается дикая угадка и восстановление.
Поддержка cronjob может быть еще более сложной, когда используются внешние инструменты, а среда не является собственной системой unix. sysadmins должны получить знания о большем количестве программ, и они могут иметь потенциальные ошибки.
я честно думаю, что это небольшой скрипт, который вы начинаете с консоли, и пусть все нормально.
<?php while(true) { $job = fetch_from_db(); if(!$job) { sleep(10) } else { $job->process(); } }
вы также можете прикоснуться к файлу (изменить временную метку модификации) в каждом цикле, и вы можете написать скрипт nagios, который проверяет, чтобы эта временная метка устарела, поэтому вы знаете, что ваша работа все еще работает …
если вы хотите, чтобы он начал работу с системой, я рекомендую деамон.
ps: в компании, которую я работаю, для нашего сайта есть много фоновой активности (обход, процессы обновления, расчеты и т. д.), и cronjobs были настоящим беспорядком, когда я начал там. они были распределены по разным серверам, отвечающим за разные задачи. к базам данных обращались дико через Интернет. тонна nfs filesytems, samba и т. д. были доступны для совместного использования ресурсов. место было полон единичных точек неудач, узких мест и чего-то постоянно ломалось. было так много технологий, что было очень сложно поддерживать, и когда что-то не работало, ему потребовались часы отслеживания проблемы и еще один час того, что эта часть даже должна была делать.
теперь у нас есть одна унифицированная программа обновления, которая отвечает за буквально все, она работает на нескольких серверах, и у них есть файл конфигурации, который определяет выполняемые задания. eveyrthing отправляется из одного родительского процесса, выполняя бесконечный цикл. его легко контролировать, настраивать, синхронизировать и все работает плавно. он избыточен, он синхронизирован и гранулярность прекрасна. поэтому он работает параллельно, и мы можем масштабировать до такого количества серверов, сколько нам нравится.
я действительно предлагаю сесть достаточно долго и подумать обо всем в целом и получить картину полной системы. затем потратьте время и силы на реализацию решения, которое будет хорошо работать в будущем и не будет распространять множество различных программ в вашей системе.
имп:
Я много читаю о минимальном интервале 1/5 минут для кроны / задач. вы можете легко обойти это с помощью произвольного сценария, который занимает этот интервал:
// 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 минут опроса не очень эффективны, в зависимости от задач, выполняемых работой.
Быстрый и грязный способ – создать цикл, который постоянно проверяет, есть ли новая работа.
Псевдопользователей-код
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 }
в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)? В этом вам нужно будет указать путь php и ваш путь к файлу php. Это работает хорошо
Не можете ли вы просто написать программу java / c ++, которая будет запрашивать вас через заданный интервал времени? Вы можете включить это в список загрузочных программ, чтобы он всегда работал. Как только задача будет найдена, она сможет обрабатывать ее на отдельном потоке и обрабатывать больше запросов и отмечать другие.
Самый простой способ – использовать встроенное расписание Windows.
Запустите свой скрипт с php-cli.exe с заполненным php.ini с расширениями, необходимыми для вашего скрипта.
Но я должен сказать, что на практике вам не нужен такой короткий промежуток времени, чтобы выполнять запланированные задания. Просто сделайте несколько тестов, чтобы получить лучшее значение интервала времени для вашего. Не рекомендуется устанавливать интервал времени менее 1 минуты.
И еще один небольшой совет: сделайте некоторый файл блокировки в начале вашего скрипта (функция php flock), проверьте наличие записи в этот файл блокировки, чтобы предотвратить работу двух или более копий одновременно, а в конце вашего скрипта отсоединить его после отпирание.
Если вам нужно записать результат вывода в БД, попробуйте использовать MySQL TRIGGERS вместо PHP. Или используйте события в MySQL.