2009-04-15 193 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();