有关PHP后台任务的想法

  最近在项目中碰到这样一个需求,PHP执行一些操作后,需要发送通知邮件,原来的代码如下:

$result_array = array('handle_action'=>$handle_action,
        'result'=> YesOrNo::YES,
        'message'=>'单据审批通过'
);
                
echo json_encode($result_array);
//处理完毕,邮件通知下一位处理人
$this->sendmailtonextaudit($bean_id, $bean_code, $status, $handle_action, $handle_opinion);
exit();   

  但是发送邮件的这步操作$this->sendmailtonextaudit()大约需要6秒多,这样前台就必须等待了,为了实现前台无需等待的需求,考虑将发送邮件的代码放到后台去执行,处理代码如下:

$result_array = array('handle_action'=>$handle_action,
    'result'=> YesOrNo::YES,
    'message'=>'单据审批通过'
);
                
while(ob_get_level())
{
    ob_end_clean();//清除之前开启了的缓冲区
}
header('HTTP/1.1 200 Ok');
header('Connection:close');//告诉浏览器,连接关闭了,这样浏览器就不用等待服务器的响应
header("Content-Encoding: none");
ignore_user_abort(true);
ob_start(); 
echo json_encode($result_array);
$size = ob_get_length();
header("Content-Length:$size");//告诉浏览器这个网页文件的长度,只有这样浏览器才会接收到相应长度的信息后中断连接
                
ob_end_flush();//输出当前缓冲
flush();//输出PHP缓冲
                
sleep(30);//休眠PHP,让php把前面的输出作完
                
set_time_limit(0);//不受时间限制
//处理完毕,邮件通知下一位处理人
$this->sendmailtonextaudit($bean_id, $bean_code, $status, $handle_action, $handle_opinion);
exit();

  相应前台代码(是用ajax调用的):

$.ajax({
    type:"POST",
    url:"/public/common/ajaxaudittrade",
    data:params,
    success: function(res){
        var obj = eval( "(" + res + ")" );
        alert(obj.message);//这一步可以很快返回
        toUrl('/trade/approved/index');
     }
});

  以上颜色加深的alert能够很快执行(不到1秒),这说明后台处理是正确的,sleep之前的内容已输出。现在问题是,后面的toUrl不会马上执行,必须等到sleep之后的代码执行完毕,才能执行toUrl。看到这里,我原先以为是前后台连接没有断开,浏览器一直在等待服务器(Apache)的响应,后来发现不是这样的。这里的连接确实已断开,之所以toUrl一直在等待,并不是它没被执行,而是执行了在等待响应而已,说的有点迷糊了吧,下面来解释下。

  web访问中,每一个会话(session)对应一个进程,上面说到的sleep后面要执行的代码和toUrl请求执行的代码,是在同一个会话下,所以它们属于同一个进程。这就导致sleep不执行完,toUrl不会执行。所以现在考虑让sleep后面的代码启用新的进程来执行,这就像“守护进程”一样,要做到:

  1.让新进程摆脱原会话的控制;

  2.让新进程摆脱原进程组的控制;

  3.让新进程摆脱原控制终端的控制;

  关于PHP中“守护进程”的用法,正在摸索中,弄明白后,会补充到这个帖子中。

 

  PS:以上纯属个人见解,如有不对,请猛喷之。

posted @ 2013-12-20 11:45  骑猪南下  阅读(438)  评论(0编辑  收藏  举报