Рассмотрим веб-приложение PHP, целью которого является прием пользовательских запросов на запуск общих асинхронных заданий, а затем создайте рабочий процесс / поток для выполнения задания. Задания не особенно интенсивны для ЦП или памяти, но, как ожидается, довольно часто будут блокироваться при вызовах ввода-вывода. В секунду следует запускать не более одного или двух заданий, но из-за длительного времени выполнения может быть много заданий, выполняемых одновременно.
Поэтому крайне важно, чтобы задания выполнялись параллельно. Кроме того, каждое задание должно контролироваться демоном-менеджером, ответственным за уничтожение зависших рабочих, прерывание рабочих процессов по запросу пользователя и т. Д.
Как лучше всего реализовать такую систему? Я вижу:
Что ж, если вы работаете в Linux, вы можете использовать pcntl_fork
для отключения детей. Затем «хозяин» наблюдает за детьми. Каждый ребенок выполняет свою задачу и затем существует нормально.
Лично мне в моих реализациях никогда не требовалась очередь сообщений. Я просто использовал в «мастере» массив с блокировками. Когда ребенок получал работу, он записывал файл блокировки с идентификационным номером задания. Затем мастер ждал, пока ребенок не выйдет. Если файл блокировки все еще существует после выхода дочернего элемента, то я знаю, что задача не была завершена, и повторно запускаю дочерний элемент с тем же заданием (после удаления файла блокировки). В зависимости от вашей ситуации вы можете реализовать очередь в простой таблице базы данных. Вставляйте задания в таблицу и проверяйте таблицу в главном устройстве каждые 30 или 60 секунд на наличие новых заданий. Затем удаляйте их из таблицы только после того, как дочерний элемент закончит (и ребенок удалил файл блокировки). Это могло бы вызвать проблемы, если бы у вас было одновременно запущено более одного «главного» файла, но вы могли бы реализовать глобальный «главный pid-файл» для обнаружения и предотвращения множественных экземпляров ...
И я бы не предлагал разветвляться с помощью FastCGI. Это может привести к некоторым очень неясным проблемам, поскольку среда предназначена для сохранения. Вместо этого используйте CGI, если у вас должен быть веб-интерфейс, но в идеале используйте приложение CLI (deamon). Для взаимодействия с ведущим устройством из других процессов вы можете либо использовать сокеты для связи TCP, либо создать файл FIFO для связи.
Что касается обнаружения зависших рабочих, вы можете реализовать систему «биения сердца», в которой дочерний процесс выдает SIG_USR1
главному процессу каждые несколько секунд. Затем, если вы не слышали от ребенка два или три раза, его можно повесить. Но дело в том, что поскольку PHP не является многопоточным, вы не можете определить, завис ли дочерний элемент или он просто ожидает блокирующего ресурса (например, вызова базы данных) ... Что касается реализации «сердцебиения» , вы можете использовать функцию тика , чтобы автоматизировать сердцебиение (но имейте в виду, что блокирующие вызовы по-прежнему не выполняются) ...