2009-04-15 117 views
14

問題:我想實現幾個正在MQ服務器隊列上偵聽異步作業的php工作進程。現在的問題是,簡單地在服務器上運行這個進程作爲守護進程並不能真正控制實例(負載,狀態,鎖定)......除了可能用於轉儲ps -aux。 因此,我正在尋找某種允許我監視和控制實例的運行時環境,無論是在系統(進程)級還是在更高層(某種Java風格的應用服務器)上,都可以監視和控制這些實例。PHP守護進程/工作環境

任何指針?

+0

另請參閱:http://symfony.com/doc/master/components/process.html – 2012-07-06 22:02:15

回答

12

下面是一些可能有用的代碼。

<? 
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

你從哪裏得到這個?開源項目或你自己的代碼?任何有關這裏究竟發生了什麼的文件或解釋? – leek 2010-09-02 23:45:16

+0

我自己的代碼。我不想解釋它,不。 – chaos 2010-09-03 06:07:55

1

您是否確實需要它持續運行?

如果您只想根據請求產生新進程,則可以在xinetd中將其註冊爲服務。

4

這聽起來像你已經有一個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 

這將使用名爲worker_1,2,3等屏幕在後臺啓動10名工人。

您可以通過運行screen -r worker_並通過使用screen -list列出正在運行的工作人員來重新附加到屏幕。

欲瞭解更多信息本指南可能會有所幫助: http://www.kuro5hin.org/story/2004/3/9/16838/14935

相關搜索:

  • 屏幕--help
  • 男子屏幕
  • google

對於生產服務器,我通常會推薦使用正常的系統啓動腳本,但我一直在運行啓動腳本的屏幕命令多年,沒有任何問題。

0

貝婁是我們@chaos答案的工作實施了pcntl插件類型的服務器守護程序。處理信號的代碼被刪除,因爲這個腳本通常只有幾毫秒。此外,在代碼中,我們添加了2個函數來保存調用之間的pid:restore_processors_state()和save_processors_state()。我們在那裏使用了redis,但是您可以決定在文件上使用實現。

我們使用cron每分鐘運行一次該腳本。 Cron檢查是否所有進程都活着。如果不是,它會重新運行它們然後死亡。如果我們想要殺死現有進程,那麼我們只需運行參數killphp script.php kill即可運行此腳本。

非常方便的方式運行工作人員沒有注入腳本到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();