验证守护程序队列管理器是否正确

时间:2017-06-09 18:07:03

标签: php signals daemon

有人可以查看我的PHP守护程序脚本或解释我如何测试它的正确性吗?我正在尝试构建一个管理进程队列的守护进程,但我需要守护进程不阻止传入的信号,我不确定我是否正确执行此操作。

另外,在守护进程中有一个while循环不断检查运行时间(通过microtime(true))会出现CPU问题吗?

<?php

declare(ticks = 1); // how often to check for signals
define("FILE_ROTATE_MAX", 5); // Max number of log files to hold

ini_set('error_reporting', E_ALL);
ini_set("display_errors", 1);

// These define the signal handling
pcntl_signal(SIGTERM, "sig_handler");
pcntl_signal(SIGHUP,  "sig_handler");
pcntl_signal(SIGINT, "sig_handler");
pcntl_signal(SIGUSR1, "sig_handler");
pcntl_signal(SIGUSR2, "sig_handler");

//PID file should only hold my process id
define('PIDFILEPATH', dirname(__FILE__) . '/pid/' . basename(__FILE__) . '.pid');
define('LOGFILEPATH', dirname(__FILE__) . '/log/' . basename(__FILE__) . '.log');

function isProcessRunning( $pidFile = PIDFILEPATH) {
    if (!file_exists($pidFile) || !is_file($pidFile)) return false;
    $pid = file_get_contents($pidFile);
    return posix_kill($pid, 0);
}

exec( 'rm -rf ' . dirname(__FILE__) . '/log/' . '*.std*' );

$cores = exec( 'nproc --all');

if( !preg_match('~^\d+$~', $cores) ){
    $cores = exec( 'grep -c ^processor /proc/cpuinfo');
    if( !preg_match('~^\d+$~', $cores) ){
        exit('Could not find number of cores on system');
    }
}

define('CORES', +$cores);
//define('MAX_PROCESSES', CORES * 2);

define('MAX_PROCESSES', 3);

if( isProcessRunning() ) {
    die("Already running?\n");
}

if( false === file_put_contents(PIDFILEPATH, posix_getpid(), LOCK_EX) ) {
    exit("Unable to write to pid file.");
}

register_shutdown_function('unlink', PIDFILEPATH);

function tick_handler() {
    pcntl_signal_dispatch();
}

register_tick_function("tick_handler");

// check to see if we need to rotate the logs

$today = new DateTime('NOW');

// 0 (for Sunday) through 6 (for Saturday)
if( $today->format('w') == '5' ) {
    if( !is_file( LOGFILEPATH . '-'. $today->format('Ymd') ) ) {
        // need to rotate the logs
        echo "need to rotate logs\n";
        $bool = rename( LOGFILEPATH, LOGFILEPATH . '-'. $today->format('Ymd') );
        if( !$bool ) {
            echo "failed to rotate logs\n";
        }
    }
}

$signalQueue = [];

function sig_handler($signo) {
    global $signalQueue;
    $signalQueue []= $signo;

    static $sigusr1_caught = 0;
    static $sigusr2_caught = 0;

    switch ($signo) {
        case SIGTERM:
            // handle shutdown tasks
            echo "Caught SIGHUP...\n";
            exit;
            break;
        case SIGHUP:
            // handle restart tasks
            echo "Caught SIGHUP...\n";
            exit;
            break;
        case SIGUSR1:
            $sigusr1_caught++;
            echo "Caught SIGUSR1...\n";
            break;
        case SIGUSR2:
            $sigusr2_caught++;
            echo "Caught SIGUSR2...\n";
            break;
        case SIGINT:
            echo "Caught SIGINT...\n";
            echo sprintf("SIGUSR1's caught - %s\n", $sigusr1_caught );
            echo sprintf("SIGUSR2's caught - %s\n", $sigusr2_caught );
            exit;
            break;
        default:
            // handle all other signals
            echo "Caught Signal Number" . $signo;
            //file_put_contents(LOGFILEPATH, "Caught Signal Number" . $signo . "\n" ,  LOCK_EX | FILE_APPEND);
            exit;
            break;
    }
}

print "Daemon - PID: ".posix_getpid() . " GID: ".posix_getgid()  ."\n";

// Do something every minute
// or start a job or something


$instances = [];

function spawnWorker($instanceID, $jobName) {
    global $instances;

    $logdir =  dirname(__FILE__) . '/log/';

    $descriptorspec = array(
        0 => array("file", $logdir . $instanceID. '.stdin'  ,"r"),  // stdin is a file that the child will read from
        1 => array("file", $logdir . $instanceID. '.stdout' ,"w"),  // stdout is a file that the child will write to
        2 => array("file", $logdir . $instanceID. '.stderr' , "a")  // stderr is a file that the child will append to
    );

    foreach($descriptorspec as $key => $innerArray) {
        touch($innerArray['1']);
        //exec(' >' . $innerArray['1']);
        chmod($innerArray['1'], 0777);
    }

    //$cwd = '/tmp';
    //$env = array('some_option' => 'aeiou');
    //$process = proc_open('php', $descriptorspec, $pipes, $cwd, $env);

    static $seconds = 10;

    $cmd = "php WorkerConfig.php {$jobName} {$seconds} ";
    $process = proc_open($cmd, $descriptorspec, $pipes);

    //$seconds = $seconds + 5;

    if (is_resource($process)) {
        $process_status = proc_get_status($process);
        $instances[$instanceID] = $process_status['pid'];
    }
}

$startTime = microtime(true);
$workerNumber = 0;
while( true ) {
    // check for max time/timeout
    $currentTime = microtime(true);
    if( ($currentTime - $startTime) > 180 ) {
        exit('max time reached');
    }
    // do work here
    // check signal queue

    while( ( count($instances) < MAX_PROCESSES ) && ($signal = array_shift($signalQueue)) ) {
        switch ($signal) {
            case SIGUSR1:
                echo "Spawning worker # {$workerNumber}\n";
                spawnWorker($workerNumber, 'Workflow');
                $workerNumber++;
                break;
            case SIGUSR2:
                echo "Caught SIGUSR2...\n";
                break;
            default:
                echo "Don't know and don't care about this signal {$signal} \n";
                break;
        }
    }

    if( count($instances) ) {
        echo 'waiting';
        $child_pid = pcntl_waitpid(0, $status, WUNTRACED);

        if( $child_pid == -1){
            echo pcntl_strerror(pcntl_get_last_error());
            exit('Error in pcntl_waitpid ');
        }
        else if( $child_pid == 0 ){
            // if WNOHANG was used and no child was available
        }
        else {
            $status = pcntl_wexitstatus($status);
            echo "Child: {$child_pid}  |  Status: {$status} \n";
            $index = array_search($child_pid, $instances);
            if( $index !== false ) {
                echo "Removing {$index}---{$child_pid} from instances array\n";
                unset($instances[$index]);
            }
        }
    }
}
exit;

0 个答案:

没有答案