原先用PHP的Pthread多線程實現的支付結果回調服務,在後期運行中出現了服務中止的問題,在學習swoole的過程當中,發現能夠用swoole的Process進程管理模塊實現多線程的功能,而且使用swoole_time_tick定時器功能實現進程監控在子進程退出的時候進行重啓。
Swoole版本:2.0.12git
PHP版本:7.1服務器
服務器版本:Ubuntu 14.04 64位微信
遊戲APP在支付後,在支付寶,微信等回調支付結果後,將支付結果回調給遊戲服務器。回調邏輯爲:25 小時之內完成 8 次通知(通知的間隔頻率通常是:0s,2m,10m,10m,1h,2h,6h,15h)。第一次通知在接收到結果時同時回調。因此另外7次間隔性回調由7個進程分別操做。每一個進程服務運行時間不一致,當前業務時間間隔各爲1s,2s,30s,30s,60s,300s,600s,600s一次swoole
use Swoole\Process; 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\n"; 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/...多線程