基於Swoole的Process程式管理模組支付結果回撥服務

wemeSky發表於2019-02-16

原先用PHP的Pthread多執行緒實現的支付結果回撥服務,在後期執行中出現了服務停止的問題,在學習swoole的過程中,發現可以用swoole的Process程式管理模組實現多執行緒的功能,並且使用swoole_time_tick定時器功能實現程式監控在子程式退出的時候進行重啟。

1、開發環境

    Swoole版本:2.0.12

    PHP版本:7.1

    伺服器版本:Ubuntu 14.04 64位

2、業務場景

    遊戲APP在支付後,在支付寶,微信等回撥支付結果後,將支付結果回撥給遊戲伺服器。回撥邏輯為:25 小時以內完成 8 次通知(通知的間隔頻率一般是:0s,2m,10m,10m,1h,2h,6h,15h)。第一次通知在接收到結果時同時回撥。所以另外7次間隔性回撥由7個程式分別操作。每個程式服務執行時間不一致,當前業務時間間隔各為1s,2s,30s,30s,60s,300s,600s,600s一次

3、程式碼例項

use SwooleProcess;

class MyProcess
{
    public $mpid = 0; // master pid, 即當前程式的程式ID
    public $works = []; // 記錄子程式的 pid
    public $maxProcessNum = 7;
    public $newIndex = 1;

    public function __construct()
    {
        try {
            swoole_set_process_name(` MyProcess : master`);
            $this->mpid = posix_getpid();
            $this->run();
            $this->processWait();
        } catch (Exception $e) {
            die(`Error: `. $e->getMessage());
        }
    }

    public function run()
    {
        //建立程式
        for ($i=0; $i<=$this->maxProcessNum; $i++) {
            $this->createProcess($i);
        }
    }


    public function createProcess($index = null)
    {
        if (is_null($index)) {
            $index = $this->newIndex;
            $this->newIndex++;
        }
        echo date(`Y-m-d H:i:s`) . `  |  createProcess index=`.$index.PHP_EOL;
        $process = new swoole_process(function (swoole_process $worker) use($index) { // 子程式建立後需要執行的函式
            swoole_set_process_name(" MyProcess : worker $index");
            //根據程式啟用不同時間間隔的定時器 $ms為毫秒 支付回撥7次嘗試 7個程式回撥服務 每次回撥的間隔時間不一致,實行25 小時以內完成 8 次通知(通知的間隔頻率一般是:2m,10m,10m,1h,2h,6h,15h)
            switch ($index) {
                case 0;
                    $ms = 1000;
                    break;
                case 1;
                    $ms = 2000;
                    break;
                case 2;
                    $ms = 30000;
                    break;
                case 3;
                    $ms = 30000;
                    break;
                case 4;
                    $ms = 60000;
                    break;
                case 5;
                    $ms = 300000;
                    break;
                case 6;
                    $ms = 600000;
                    break;
                case 7;
                    $ms = 600000;
                    break;
            }
            //啟用定時器
            $timer=swoole_timer_tick($ms,`MyProcess::deal_pay_notify`, $index);

        }, false, false); // 不重定向輸入輸出; 不使用管道
        $pid = $process->start();
        $this->works[$index] = $pid;
        return $pid;
    }

    /*
        * 處理支付回撥
        */
    function deal_pay_notify($timmerID, $params){
        echo date(`Y-m-d H:i:s`) . `  |  timmerID=`.$timmerID." params=".$params.PHP_EOL;

        //支付結果回撥操作
        //......

    }

    // 重啟子程式
    public function rebootProcess($pid)
    {
        $index = array_search($pid, $this->works);
        if ($index !== false) {
            //重新建立程式
            $newPid = $this->createProcess($index);
            echo "rebootProcess: {$index}={$pid}->{$newPid} Done
";
            return;
        }
        throw new Exception("rebootProcess error: no pid {$pid}");
    }


    // 監控子程式
    public function processWait()
    {
        //定時器每秒監控
        swoole_timer_tick(1000,`MyProcess::monitor_process`, ``);
        /*while (1) {
            if (count($this->works)) {
                $ret = Process::wait(); // 子程式退出
                if ($ret) {
                    $this->rebootProcess($ret[`pid`]);
                }
            } else {
                break;
            }
        }*/
    }

    //檢測程式
    public function monitor_process($timmerID, $params){
        foreach($this->works as $pid){
            if (!Process::kill($pid, 0)) { // 0 可以用來檢測程式是否存在
                $this->rebootProcess($pid); //重啟程式
                echo date(`Y-m-d H:i:s`) . `  |  monitor_process pid=`.$pid. ` restart`.PHP_EOL;
            }
        }
    }
}

new MyProcess();

gitee:https://gitee.com/oydm/codes/…

相關文章