在我之前的文章中,介绍过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守护进程的更多相关文章

  1. Linux Rsync备份服务介绍及部署守护进程模式

    rsync介绍 rsync是一款开源的.快速的.多功能的.可实现全量及增量的本地或远程数据同步备份工具 在常驻模式(daemon mode)下,rsync默认监听TCP端口873,以原生rsync传输 ...

  2. linux分享六:nohup与&amp;,守护进程

    contab每秒执行脚本,然后将把标准错误重定向到标准输出(2>&1)以追加的方式写入log_cronjob.txt.补充:试想2>1代表什么,2与>结合代表错误重定向,而1 ...

  3. 编写Linux/Unix守护进程

    原文: http://www.cnblogs.com/haimingwey/archive/2012/04/25/2470190.html 守护进程在Linux/Unix系统中有着广泛的应用.有时,开 ...

  4. linux系统编程之进程(八):守护进程详解及创建,daemon()使用

    一,守护进程概述 Linux Daemon(守护进程)是运行在后台的一种特殊进程.它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件.它不需要用户输入就能运行而且提供某种服务,不是对整个 ...

  5. 创建守护进程步骤与setsid() -- linux deamon进程

    原创:http://www.cnblogs.com/mickole/p/3188321.html 一,守护进程概述 Linux Daemon(守护进程)是运行在后台的一种特殊进程.它独立于控制终端并且 ...

  6. Linux守护进程详解(init.d和xinetd) [转]

    一 Linux守护进程 Linux 服务器在启动时需要启动很多系统服务,它们向本地和网络用户提供了Linux的系统功能接口,直接面向应用程序和用户.提供这些服务的程序是由运行在后台 的守护进程来执行的 ...

  7. 深入理解Linux操作系统守护进程的意义

    Linux服务器在启动时需要启动很多系统服务,它们向本地和网络用户提供了Linux的系统功能接口,直接面向应用程序和用户.提供这些服务的程序是由运行在后台的守护进程(daemons)来执行的.守护进程 ...

  8. Linux守护进程详解(init.d和xinetd)

    一 Linux守护进程 Linux 服务器在启动时需要启动很多系统服务,它们向本地和网络用户提供了Linux的系统功能接口,直接面向应用程序和用户.提供这些服务的程序是由运行在后台的守护进程来执行的. ...

  9. 用C#编写Linux守护进程

    如果要在Red Hat Enterprise Linux上将.NET Core进程作为后台进程运行,则可以创建自定义systemd单元.今天我将为.NET Core编写两个自定义系统单元的例子.一个是 ...

随机推荐

  1. 前端forEach在Array、map、set中的使用

    数组: var s = ['a','b','c']; s.forEach(function(ele,index,array){ console.log(ele); }); Map: var map = ...

  2. (DFS、bitset)AOJ-0525 Osenbei

    题目地址 简要题意: 给出n行m列的0.1矩阵,每次操作可以将任意一行或一列反转,即这一行或一列中0变为1,1变为0.问通过任意多次这样的变换,最多可以使矩阵中有多少个1. 思路分析: 行数比较小,先 ...

  3. C语言程序设计第七次作业

    一.学习内容     本次课学习了函数的基本知识,需要大家对如下知识点进行总结:     1. 函数定义的基本格式,函数定义和函数原型(声明)的区别何在?     2. 函数的调用方式有哪几种     ...

  4. 数据结构和算法 &ndash; 3.堆栈和队列

    1.栈的实现   后进先出     自己实现栈的代码 using System; using System.Collections.Generic; using System.Linq; using ...

  5. 利用JS提交表单的几种方法和验证

    第一种方式:表单提交,在form标签中增加onsubmit事件来判断表单提交是否成功 <script type="text/javascript"> function ...

  6. js 数组 转

    1.数组的创建 var arrayObj = new Array(); //创建一个数组 var arrayObj = new Array([size]); //创建一个数组并指定长度,注意不是上限, ...

  7. Asp.net MVC 中Controller返回值类型ActionResult

    [Asp.net MVC中Controller返回值类型] 在mvc中所有的controller类都必须使用"Controller"后缀来命名并且对Action也有一定的要求: 必 ...

  8. Linux Shell查看磁盘分区,内存使用,CPU使用率

    Linux Shell查看磁盘分区,内存使用,CPU使用率 #!/bin/bash #disk_used_rate Location=/dev/xvdb Disk_Used_Rate=$(df -h ...

  9. Google邮箱:Gmail国际顶级邮箱

    本博文的主要内容有 .Google邮箱的介绍   1.Google邮箱的介绍 https://zh.wikipedia.org/wiki/Gmail http://mail/google.com/ h ...

  10. JavaScript高级程序设计:第十章

    一.理解包含不同层次节点的DOM 1.节点层次 以下面的HTML为例: <html> <head> <title>Sample Page</title> ...