2009-04-15 14 views
14

Problem: Chcę zaimplementować kilka procesów php-worker, które nasłuchują na kolejce MQ-server dla asynchronicznych zadań. Problem polega na tym, że po prostu uruchamianie tych procesów jako demonów na serwerze naprawdę nie daje mi żadnego poziomu kontroli nad instancjami (Load, Status, locked up) ... z wyjątkiem być może wyrzucania ps -aux. Z tego powodu szukam środowiska wykonawczego, które pozwala mi monitorować i kontrolować instancje, na poziomie systemowym (procesowym) lub na wyższej warstwie (pewien rodzaj aplikacji Java w stylu)PHP Demon/środowisko robocze

Dowolny wskaźniki?

+0

Zobacz także: http://symfony.com/doc/master/components/process.html –

Odpowiedz

12

Oto kod, który może być przydatny.

<? 
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(); 
?> 
+0

Skąd to masz? Projekt open source lub własny kod? Wszelka dokumentacja lub wyjaśnienie, co dokładnie się tutaj dzieje? – leek

+0

Mój własny kod. Nie jestem skłonny tego tłumaczyć, nie. – chaos

+0

Również https://github.com/kvz/system_daemon. – HyderA

1

Czy rzeczywiście trzeba go mieć stale działa?

Jeśli chcesz tylko odrodzić nowy proces na żądanie, możesz zarejestrować go jako usługę w xinetd.

+0

Aspekt odradzania nie jest dużym problemem, ponieważ liczba pracowników zależy od wydajności systemu, która jest zwykle stała. Ważniejszy byłby aspekt monitorowania indywidualnego statusu pracownika (rozbił się, cokolwiek). Jednym z odkrytych przeze mnie narzędzi może być deamontools DJBs – Sebastian

+0

To jedna opcja. Do monitorowania można również użyć flock() - ed plików PID. Po zawieszeniu wszystkie blokady zostaną zwolnione. – vartec

4

Wygląda na to, że masz już MQ uruchomiony na systemie * nix i chcesz tylko zarządzać pracownikami.

Bardzo prostym sposobem na to jest użycie ekranu GNU. Aby rozpocząć 10 pracowników, możesz użyć:

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

Rozpocznie to 10 pracowników w tle przy użyciu ekranów o nazwie worker_1,2,3 i tak dalej.

Możesz ponownie dołączyć do ekranów, uruchamiając ekran -r worker_ i wyświetla listę działających pracowników, korzystając z listy ekranów.

uzyskać więcej informacji na ten przewodnik może być pomocne: http://www.kuro5hin.org/story/2004/3/9/16838/14935

Spróbuj również:

  • ekranem --help
  • ekran człowiek
  • lub google.

Dla serwerów produkcyjnych normalnie zaleca się używanie normalnych skryptów startowych systemu, ale od lat uruchamiam polecenia ekranowe ze skryptów startowych bez żadnych problemów.

0

Bellow jest nasza realizacja robocza @chaos odpowiedź. Kod do obsługi sygnałów został usunięty, ponieważ ten skrypt zwykle trwa zaledwie kilka milisekund.

Ponadto w kodzie dodaliśmy 2 funkcje do zapisywania pidów między wywołaniami: restore_processors_state() i save_processors_state(). Użyliśmy tam redis, ale możesz zdecydować się na implementację plików.

Uruchomimy ten skrypt co minutę za pomocą crona. Cron sprawdza, czy wszystkie procesy są żywe. Jeśli nie - uruchamia je ponownie, a następnie umiera. Jeśli chcemy zabić istniejące procesy, po prostu uruchamiamy ten skrypt z argumentem kill: php script.php kill.

Bardzo przydatny sposób uruchamiania pracowników bez wstrzykiwania skryptów do 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(); 
Powiązane problemy