Вопрос

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

Есть какие-нибудь указания?

Это было полезно?

Решение

Вот код, который может быть полезен.

<?
define('WANT_PROCESSORS', 5);
define('PROCESSOR_EXECUTABLE', '/path/to/your/processor');
set_time_limit(0);
$cycles = 0;
$run = true;
$reload = false;
declare(ticks = 30);

function signal_handler($signal) {
    switch($signal) {
    case SIGTERM :
        global $run;
        $run = false;
        break;
    case SIGHUP  :
        global $reload;
        $reload = true;
        break;
    }   
}

pcntl_signal(SIGTERM, 'signal_handler');
pcntl_signal(SIGHUP, 'signal_handler');

function spawn_processor() {
    $pid = pcntl_fork();
    if($pid) {
        global $processors;
        $processors[] = $pid;
    } else {
        if(posix_setsid() == -1)
            die("Forked process could not detach from terminal\n");
        fclose(stdin);
        fclose(stdout);
        fclose(stderr);
        pcntl_exec(PROCESSOR_EXECUTABLE);
        die('Failed to fork ' . PROCESSOR_EXECUTABLE . "\n");
    }
}

function spawn_processors() {
    global $processors;
    if($processors)
        kill_processors();
    $processors = array();
    for($ix = 0; $ix < WANT_PROCESSORS; $ix++)
        spawn_processor();
}

function kill_processors() {
    global $processors;
    foreach($processors as $processor)
        posix_kill($processor, SIGTERM);
    foreach($processors as $processor)
        pcntl_waitpid($processor);
    unset($processors);
}

function check_processors() {
    global $processors;
    $valid = array();
    foreach($processors as $processor) {
        pcntl_waitpid($processor, $status, WNOHANG);
        if(posix_getsid($processor))
            $valid[] = $processor;
    }
    $processors = $valid;
    if(count($processors) > WANT_PROCESSORS) {
        for($ix = count($processors) - 1; $ix >= WANT_PROCESSORS; $ix--)
            posix_kill($processors[$ix], SIGTERM);
        for($ix = count($processors) - 1; $ix >= WANT_PROCESSORS; $ix--)
            pcntl_waitpid($processors[$ix]);
    } elseif(count($processors) < WANT_PROCESSORS) {
        for($ix = count($processors); $ix < WANT_PROCESSORS; $ix++)
            spawn_processor();
    }
}

spawn_processors();

while($run) {
    $cycles++;
    if($reload) {
        $reload = false;
        kill_processors();
        spawn_processors();
    } else {
        check_processors();
    }
    usleep(150000);
}
kill_processors();
pcntl_wait();
?>

Другие советы

Похоже, что у вас уже есть MQ, работающий в системе *nix, и вам просто нужен способ управления рабочими процессами.

Очень простой способ сделать это — использовать экран GNU.Чтобы запустить 10 рабочих, вы можете использовать:

#!/bin/sh
for x in `seq 1 10` ; do
screen -dmS worker_$x php /path/to/script.php worker$x
end

Это запустит 10 рабочих процессов в фоновом режиме, используя экраны с именами worker_1,2,3 и так далее.

Вы можете повторно подключиться к экранам, запустив screen -r worker_, и просмотреть список запущенных рабочих процессов с помощью screen -list.

Для получения дополнительной информации это руководство может быть полезным:http://www.kuro5hin.org/story/2004/3/9/16838/14935

Также попробуйте:

  • экран --помощь
  • экран человека
  • или Google.

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

Вам действительно нужно, чтобы он работал постоянно?

Если вы хотите запускать новый процесс только по запросу, вы можете зарегистрировать его как службу в xinetd.

серверный демон типа плагина pcntl для PHP

http://dev.pedemont.com/sonic/

Ниже приведена наша рабочая реализация ответа @chaos.Код для обработки сигналов был удален, поскольку этот скрипт обычно живет всего несколько миллисекунд.

Кроме того, в код мы добавили 2 функции для сохранения pid между вызовами:restore_processors_state() и save_processors_state().Мы использовали redis там, но вы можете решить использовать реализацию для файлов.

Мы запускаем этот скрипт каждую минуту, используя cron.Cron проверяет, все ли процессы активны.Если нет - он повторно запускает их, а затем умирает.Если мы хотим уничтожить существующие процессы, то мы просто запускаем этот скрипт с аргументом kill: php script.php kill.

Очень удобный способ запуска workers без внедрения скриптов в init.d.

<?php

include_once dirname( __FILE__ ) . '/path/to/bootstrap.php';

define('WANT_PROCESSORS', 5);
define('PROCESSOR_EXECUTABLE', '' . dirname(__FILE__) . '/path/to/worker.php');
set_time_limit(0);

$run = true;
$reload = false;
declare(ticks = 30);

function restore_processors_state()
{
    global $processors;

    $redis = Zend_Registry::get('redis');
    $pids = $redis->hget('worker_procs', 'pids');

    if( !$pids )
    {
        $processors = array();
    }
    else
    {
        $processors = json_decode($pids, true);
    }
}

function save_processors_state()
{
    global $processors;

    $redis = Zend_Registry::get('redis');
    $redis->hset('worker_procs', 'pids', json_encode($processors));
}

function spawn_processor() {
    $pid = pcntl_fork();
    if($pid) {
        global $processors;
        $processors[] = $pid;
    } else {
        if(posix_setsid() == -1)
            die("Forked process could not detach from terminal\n");
        fclose(STDIN);
        fclose(STDOUT);
        fclose(STDERR);
        pcntl_exec('/usr/bin/php', array(PROCESSOR_EXECUTABLE));
        die('Failed to fork ' . PROCESSOR_EXECUTABLE . "\n");
    }
}

function spawn_processors() {
    restore_processors_state();

    check_processors();

    save_processors_state();
}

function kill_processors() {
    global $processors;
    foreach($processors as $processor)
        posix_kill($processor, SIGTERM);
    foreach($processors as $processor)
        pcntl_waitpid($processor, $trash);
    unset($processors);
}

function check_processors() {
    global $processors;
    $valid = array();
    foreach($processors as $processor) {
        pcntl_waitpid($processor, $status, WNOHANG);
        if(posix_getsid($processor))
            $valid[] = $processor;
    }
    $processors = $valid;
    if(count($processors) > WANT_PROCESSORS) {
        for($ix = count($processors) - 1; $ix >= WANT_PROCESSORS; $ix--)
            posix_kill($processors[$ix], SIGTERM);
        for($ix = count($processors) - 1; $ix >= WANT_PROCESSORS; $ix--)
            pcntl_waitpid($processors[$ix], $trash);
    }
    elseif(count($processors) < WANT_PROCESSORS) {
        for($ix = count($processors); $ix < WANT_PROCESSORS; $ix++)
            spawn_processor();
    }
}

if( isset($argv) && count($argv) > 1 ) {
    if( $argv[1] == 'kill' ) {
        restore_processors_state();
        kill_processors();
        save_processors_state();

        exit(0);
    }
}

spawn_processors();
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top