博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

swoole创建工作进程,执行滞后工作

Posted on 2017-11-02 16:29  懒人ABC  阅读(975)  评论(0编辑  收藏  举报

一,创建守候进程,因为这里不需要Server,也没有Client,数据交换通过redis进行

<?php
namespace Kuba\Saas;
require_once __DIR__ . '/Core/ErrorHandle.php';
use \Swoole\Timer;
use \Swoole\Process;
use Kuba\Saas\Core\ErrorHandle;

final class Services {

    private $m_workers = [];
    private $m_pid = 0;
	
    public function __construct() {
        try {
            $this->m_pid = posix_getpid();
            
            echo "moolan_services start:".$this->m_pid.PHP_EOL;
            echo date("Y-m-d H:i:s").PHP_EOL;
            
            \swoole_set_process_name("moolan_services");

            $this->create_error_monitor_process($this->m_pid);

            //监控子进程的状态,如果子进程异常退出,则重启该子进程
            $this->process_monitor();
        }catch (\Exception $e){
            die('ALL ERROR: '.$e->getMessage());
        }        
    }
    
    private function process_monitor()
    {       
        //检测子进程是否结束,如果结束,则重新启动子进程 
        while(1) {
            if(count($this->m_workers)){
                //这里会一直等待,一次接收一个子进程,所以外面必须有循环
                $ret = \swoole_process::wait();
                if ($ret) {
                    $this->process_reboot($ret);
                }
            }             
        }        
    }
    
    private function process_reboot($ret){
        try
        {
            $pid=$ret['pid'];

            if(in_array($pid, $this->m_workers)){
                $method_name = $this->m_workers[$pid];
                unset($this->m_workers[$pid]);

                echo $method_name." restart:".$pid.PHP_EOL;
                echo date("Y-m-d H:i:s").PHP_EOL;                
                
                $method = new \ReflectionMethod($this, $method_name);
                $method->invoke($this, [$this->m_pid]);

                return;
            }
        }
        catch (\Exception $e)
        {
            die('Process_reboot error: '.$e->getMessage());
        }
    }    
    
    /**
     * 创建监控系统错误的进程
     * 
     * 该进程属于一条一条处理的模式,因为错误不会太多
     */
    private function create_error_monitor_process($mpid)
    {
        try
        {
            $process = new Process(function ($worker) use ($mpid)
            {
                try
                {               
                    \swoole_set_process_name("moolan_error_handle");

                    $obj_error_handle = new ErrorHandle();
                    while (true)
                    {
                        try
                        {
                            //从消息队列接收出错消息,接收到一个,就启动一个task去执行                
                            //如果接收不到出错信息,则休息2秒时间
                            if (!$obj_error_handle->fetch_task())
                            {
                                $obj_error_handle->release_task();
                                unset($obj_error_handle);

                                usleep(2000000);

                                $obj_error_handle = new ErrorHandle();
                            }
                            else
                            {
                                //启动任务处理接收到的出错信息
                                $obj_error_handle->do_task();
                            }

                            //执行完一个完成的任务后,
                            //查看主进程是否已经关闭,如果已经关闭,则子进程也要关闭运行
                            if(!\swoole_process::kill($mpid,0)){
                                echo 'moolan service gone'.PHP_EOL;
                                echo __METHOD__.' process exit'.PHP_EOL;
                                $worker->exit();
                            }
                        }
                        catch (\Exception $e)
                        {
                            echo $e->getMessage();
                        }
                    }   
                }
                catch (\Exception $e)
                {
                    die(__METHOD__.' process exec error: '.$e->getMessage());
                }
            }, false);

            $pid = $process->start();
            
            echo __METHOD__." started:".$pid.PHP_EOL;
            echo date("Y-m-d H:i:s").PHP_EOL;             
            
            $this->m_workers[$pid] = __METHOD__;
        }
        catch (\Exception $e)
        {
            die(__METHOD__.' Process Start error: '.$e->getMessage());
        }
    }

}

$server = new Services();

  二,创建值守脚本,检测以上主进程持续运行

#! /bin/sh

proc_name="***"                    # 进程名
proc_file="***.php"
log_name="/***/moolan-monitor.log"                  # 日志文件
pid=0

proc_num()                                             # 计算进程数
{
        num=`ps -ef | grep $proc_name | grep -v grep | wc -l`
        return $num
}

proc_id()                                               # 进程号
{
        pid=`ps -ef | grep $proc_name | grep -v grep | awk '{print $2}'`
}

proc_num
number=$?
if [ $number -eq 0 ]                                    # 判断进程是否存在
then 
        nohup /usr/local/php5/bin/php /***/$proc_file >>$log_name 2>&1 &                 # 重启进程的命令,请相应修改
        proc_id                                               # 获取新进程号
        echo ${pid}, `date` >>  $log_name                    # 将新进程号和重启时间记录
fi

  三,把值守脚本加入到定时器

crontab

利用定时任务来轮询执行脚本

*/1 * * * * /PATH/watch_queue.sh