• [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 ... 
    ";
    
        sleep(5);
    
        print "Worker's task done ... 
    ";
    
        $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 
    ";
    
                exit(0);
    
                break;
    
            case SIGSTOP:
    
                print date('y-m-d H:i:s', time() ) . " Caught Signal : SIGSTOP - No : $signal 
    ";
    
                break;
    
            case SIGHUP:
    
                print date('y-m-d H:i:s', time() ) . " Caught Signal : SIGHUP - No : $signal 
    ";
    
                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 
    ";
    
                //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. 
    ";
    
            $pid = pcntl_fork();
    
            if( $pid == -1 ){
    
                print "Fork error 
    ";
    
            }else if( $pid > 0 ){
    
                print "Parent exit 
    ";
    
                exit(0);
    
            }else{
    
                $init_md5 = md5_file( $filename );
    
                print "Child continue to run 
    ";
    
            }
    
        }
    
    }
    

      

    参考资料:
     
    再参考一下下面的片段:
     
    <?php
    
    function handle_http_request($address, $port){
    	$max_backlog = 16;
    	$res_content = "HTTP/1.1 200 OK 
    ".
    				   "Content-Length: 15 
    ".
    				   "Content-Type: text/plain; charset=UTF-8 
    ".
    				   "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!
    ";
    		exit;
    	}
    
    	if((socket_bind($socket, $address, $port)) === FALSE)
    	{
    		echo "Bind socket failed!
    ";
    		exit;
    	}
    
    	if((socket_listen($socket, $max_backlog)) === FALSE)
    	{
    	echo "Listen to socket failed!
    ";
    	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();
    ?>
    

      

  • 相关阅读:
    【转】常用插件的使用—grunt入门指南(上)
    基于Cordova的android项目入门
    【转】隐藏元素的子元素隐藏无效
    【转】IE7以下绝对定位被某元素遮挡
    关于“No projects are found to import”的解决方法
    【转】IE6中a标签触发图片和ajax请求被abort
    JS小笔记
    mysql删除重复数据
    国内优秀的团队技术博客
    mysql中的union和order by、limit
  • 原文地址:https://www.cnblogs.com/yiyide266/p/5538202.html
Copyright © 2020-2023  润新知