Иногда бывает нужно держать определенное количество процессов в работе.
Это можно реализовать через крон, который запускается раз в минуту, но как показала практика это не лучшее решение.
Предлагаю более технологичный вариант:
<?php
// создаем дочерний процесс
$child_pid = pcntl_fork();
if ($child_pid) {
// выходим из родительского, привязанного к консоли, процесса
exit;
}
// делаем основным процессом дочерний
// После этого он тоже cможет создавать процессы
posix_setsid();
//чтобы повторно не запустить демона, нужна функция для проверки его pid
function isDaemonActive($pid_file) {
if (is_file($pid_file)) {
$pid = file_get_contents($pid_file);
//проверяем на наличие процесса
if (posix_kill($pid, 0)) {
//демон уже запущен
return true;
} else {
//pid-файл есть, но процесса нет
if (!unlink($pid_file)) {
//не могу уничтожить pid-файл. ошибка
exit(-1);
}
}
}
return false;
}
//проверяем запущен ли демон
if (isDaemonActive(__DIR__ . '/daemon.pid')) {
echo 'Daemon already active';
exit;
}
//регистрируем обработчик сигналов
pcntl_signal(SIGTERM, "sigHandler");
//сама функция обработчика
function sigHandler($signo) {
global $stop_server;
switch ($signo) {
case SIGTERM: {
$stop_server = true;
break;
}
default: {
//все остальные сигналы
}
}
}
//говорим php принимать сигналы
pcntl_signal_dispatch();
//записываем pid процесса демона
file_put_contents(__DIR__ . '/daemon.pid', getmypid());
//будем держать не более 20 процессов одновременно
define('MAX_CHILD_PROCESSES', 20);
//задержка чтобы не гонять цикл постоянно
define('DELAY', 1);
//массив для хранения дочерних процессов
$child_processes = array();
//запускаем бесконечный цикл
while (!$stop_server) {
if (!$stop_server and (count($child_processes) < MAX_CHILD_PROCESSES)) {
//плодим дочерний процесс
$pid = pcntl_fork();
if ($pid == -1) {
//ошибка - не смогли создать процесс
} elseif ($pid) {
//процесс создан
$child_processes[$pid] = true;
} else {
$pid = getmypid();
//дочерний процесс - тут рабочая нагрузка
//для примера заснем на 100
//на этом месте может быть, например, команда конвертации видео
sleep(100);
exit;
}
} else {
//чтоб не гонять цикл постоянно
sleep(DELAY);
}
//проверяем, умер ли один из детей
while ($signaled_pid = pcntl_waitpid(-1, $status, WNOHANG)) {
if ($signaled_pid == -1) {
//детей не осталось
$child_processes = array();
break;
} else {
unset($child_processes[$signaled_pid]);
}
}
}
Осталось только запустить демона
php daemon.php
Если все сделано верно, то будет постоянно висеть 20 процессов.
Убить такого демона можно опять же из php
<?php
//НАПРИМЕР pid демона 56497
posix_kill(56497, 9);