代码之家  ›  专栏  ›  技术社区  ›  Sebastian

php守护进程/工作环境

  •  14
  • Sebastian  · 技术社区  · 16 年前

    问题:我想实现几个PHP工作进程,这些进程正在监听一个用于异步作业的MQ服务器队列。现在的问题是,仅仅在服务器上以守护进程的形式运行这个进程并不能真正给我对实例(加载、状态、锁定)的任何控制级别……除了转储ps-aux。 正因为如此,我正在寻找一种运行时环境,它可以监视和控制系统(进程)级别或更高层(某种Java风格的AppServer)上的实例。

    有什么指针吗?

    5 回复  |  直到 11 年前
        1
  •  12
  •   chaos    16 年前

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

    <?
    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();
    ?>
    
        2
  •  4
  •   Morgan Christiansson    16 年前

    听起来您已经在*nix系统上启动并运行了一个MQ,只想找到一种管理工人的方法。

    一个非常简单的方法就是使用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_u重新连接到屏幕,并使用screen-list列出正在运行的工作人员。

    有关详细信息,本指南可能有帮助: http://www.kuro5hin.org/story/2004/3/9/16838/14935

    也尝试:

    • 屏幕帮助
    • 人机界面
    • google .

    对于生产服务器,我通常建议使用正常的系统启动脚本,但是我已经运行启动脚本中的屏幕命令多年,没有出现任何问题。

        3
  •  1
  •   vartec    16 年前

    你真的需要它连续运行吗?

    如果您只想根据请求生成新进程,那么可以在xinetd中将其注册为服务。

        4
  •  1
  •   user117776    16 年前

    用于php的pcntl插件类型服务器守护程序

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

        5
  •  0
  •   Vitaly Dyatlov    11 年前

    以下是我们对@chaos answer的工作实现。处理信号的代码被删除,因为该脚本通常只存在几毫秒。

    另外,在代码中,我们添加了两个函数来保存调用之间的PID:restore_processors_state()和save_processors_state()。我们已经用过 redis 但您可以决定在文件上使用实现。

    我们使用cron每分钟运行一次这个脚本。cron检查所有进程是否都处于活动状态。如果不是-它会重新运行它们然后死亡。如果我们想终止现有的进程,那么我们只需使用参数运行这个脚本 kill : php 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();
    
    推荐文章