[Linux]使用PHP编写Gearman的Worker守护进程

Posted yiyide266

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Linux]使用PHP编写Gearman的Worker守护进程相关的知识,希望对你有一定的参考价值。

在我之前的文章中,介绍过Gearman的使用。在我的项目中,我使用了php来编写一直运行的Worker。如果按照Gearman官方推荐的例子,只是简单的一个循环来等待任务,会有一些问题,包括:1、当代码进行过修改之后,如何让代码的修改生效;2、重启Worker的时候,如何保证当前的任务处理完成才重启。
 
针对这个问题,我考虑了以下的解决方法:
1、每次修改完代码后,Worker需要手工重启(先杀死然后启动)。这个只能解决重新加载配置文件的问题。
2、在Worker中设置,单次任务循环完成后,就对Worker进行重启。这个方案的问题在于消耗比较大。
3、在Worker中添加一个退出函数,如果需要Worker退出的时候,在Client端发送一个优先级比较高的退出调用。这个需要客户端配合,在使用后台类任务时,不太适合。
4、在Worker中检查文件是否发生变化,如果发生了变化,退出并重启自身。
5、为Worker编写信号控制,接受重启指令,类似于 http restart graceful 指令。
 
最后,结合4和5两种方法,可以实现这样一个Daemon,如果配置文件发生了变化,他就会自动重启;如果接受到了用户的 kill  -1 pid 信号,也会重新启动。
 
代码如下:
 
<?php



declare( ticks = 1 );

// This case will check the config file regularly, if the config file changed, it will restart it self

// If you want to restart the daemon gracefully, give it a HUP signal

// by shiqiang<cocowool@gmail.com> at 2011-12-04



$init_md5 = md5_file( \'config.php\');



// register signal handler

pcntl_signal( SIGALRM, "signal_handler", true );

pcntl_signal( SIGHUP, \'signal_handler\', TRUE );



$job_flag = FALSE;    //Job status flag, to justify if the job has been finished

$signal_flag = FALSE;    //Signal status flag, to justify whether we received the kill -1 signal



while( 1 ){

    $job_flag = FALSE;    //Job status flag

    print "Worker start running ... \\n";

    sleep(5);

    print "Worker\'s task done ... \\n";

    $flag = TRUE;    //Job status flag

    AutoStart( $signal_flag );

}



function signal_handler( $signal ) {

    global $job_flag;

    global $signal_flag;



    switch( $signal ){

        case SIGQUIT:

            print date(\'y-m-d H:i:s\', time() ) . " Caught Signal : SIGQUIT - No : $signal \\n";

            exit(0);

            break;

        case SIGSTOP:

            print date(\'y-m-d H:i:s\', time() ) . " Caught Signal : SIGSTOP - No : $signal \\n";

            break;

        case SIGHUP:

            print date(\'y-m-d H:i:s\', time() ) . " Caught Signal : SIGHUP - No : $signal \\n";

            if( $flag === TRUE ){

                AutoStart( TRUE );

            }else{

                $signal_flag = TRUE;

            }

            break;

        case SIGALRM:

            print date(\'y-m-d H:i:s\', time() ) . " Caught Signal : SIGALRM - No : $signal \\n";

            //pcntl_exec( \'/bin/ls\' );

            pcntl_alarm( 5 );

            break;

        default:

            break;

    }

}



function AutoStart( $signal = FALSE, $filename = \'config.php\' ){

    global $init_md5;



    if( $signal || md5_file( $filename ) != $init_md5 ){

        print "The config file has been changed, we are going to restart. \\n";

        $pid = pcntl_fork();

        if( $pid == -1 ){

            print "Fork error \\n";

        }else if( $pid > 0 ){

            print "Parent exit \\n";

            exit(0);

        }else{

            $init_md5 = md5_file( $filename );

            print "Child continue to run \\n";

        }

    }

}

  

参考资料:
 
再参考一下下面的片段:
 
<?php

function handle_http_request($address, $port){
	$max_backlog = 16;
	$res_content = "HTTP/1.1 200 OK \\n".
				   "Content-Length: 15 \\n".
				   "Content-Type: text/plain; charset=UTF-8 \\n".
				   "PHP HTTP Server Hello World!!";
	$res_len = strlen($res_content);

	//Create, bind and listen to socket
	if(($socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === FALSE){
		echo "Create socket failed!\\n";
		exit;
	}

	if((socket_bind($socket, $address, $port)) === FALSE)
	{
		echo "Bind socket failed!\\n";
		exit;
	}

	if((socket_listen($socket, $max_backlog)) === FALSE)
	{
	echo "Listen to socket failed!\\n";
	exit;
	}

	//loop
	while (true) {
		if( ($accept_socket = socket_accept($socket)) === FALSE ){
			continue;
		}else{
			socket_write($accept_socket, $res_content, $res_len);
			socket_close($accept_socket);
		}
	}


}


//Run as daemon process.
function run(){

	if(($pid1 = pcntl_fork()) === 0){

		posix_setsid();//Set first child process as the session leader.

		if(($pid2 = pcntl_fork()) === 0){
			handle_http_request(\'192.168.255.131\', 10101);
		}else{
			exit;
		}
	}else{
		pcntl_wait($status);
	}
}


run();
?>

  

以上是关于[Linux]使用PHP编写Gearman的Worker守护进程的主要内容,如果未能解决你的问题,请参考以下文章

php使用gearman进行任务分发

PHP-Java 互操作 - Gearman 还是 PJB?

mac下快速安装gearman和php扩展

php异步任务处理: gearman

Gearman使用示例

安装 gearman