Пишем демона на php

Иногда бывает нужно держать определенное количество процессов в работе.
Это можно реализовать через крон, который запускается раз в минуту, но как показала практика это не лучшее решение.
Предлагаю более технологичный вариант:
<?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);