/** * 监控worker进程状态,退出重启 * @param resource $channel * @param int $flag * @param int $pid 退出的进程id */ public static function monitorWorkers($wait_pid = -1) { // 由于SIGCHLD信号可能重叠导致信号丢失,所以这里要循环获取所有退出的进程id while (($pid = pcntl_waitpid($wait_pid, $status, WUNTRACED | WNOHANG)) != 0) { // 如果是重启的进程,则继续重启进程 if (isset(self::$workerToRestart[$pid]) && self::$serverStatus != self::STATUS_SHUTDOWN) { Telnet::sendToAllClient("."); unset(self::$workerToRestart[$pid]); self::restartWorkers(); } // 出错 if ($pid == -1) { // 没有子进程了,可能是出现Fatal Err 了 if (pcntl_get_last_error() == 10) { self::notice('Server has no workers now'); } return -1; } // 查找子进程对应的woker_name $pid_workname_map = self::getPidWorkerNameMap(); $worker_name = isset($pid_workname_map[$pid]) ? $pid_workname_map[$pid] : ''; // 没找到worker_name说明出错了 哪里来的野孩子? if (empty($worker_name)) { self::notice("child exist but not found worker_name pid:{$pid}"); break; } // 进程退出状态不是0,说明有问题了 if ($status !== 0 && self::$serverStatus != self::STATUS_SHUTDOWN) { self::notice("worker exit status {$status} pid:{$pid} worker:{$worker_name}"); } // 记录进程退出状态 self::$serverStatusInfo['err_info'][$worker_name][$status] = isset(self::$serverStatusInfo['err_info'][$worker_name][$status]) ? self::$serverStatusInfo['err_info'][$worker_name][$status] + 1 : 1; // 清理这个进程的数据 self::clearWorker($worker_name, $pid); // 如果服务是不是关闭中 if (self::$serverStatus != self::STATUS_SHUTDOWN) { // 重新创建worker self::createWorkers(); // 开发环境需要上报监控文件给FileMonitor if ($worker_name == 'FileMonitor') { Reporter::reportIncludedFiles(self::$filesToInotify); } } else { $all_worker_pid = self::getPidWorkerNameMap(); if (empty($all_worker_pid)) { // 发送提示 self::notice("Server stoped"); // 关闭管理员socket Telnet::close(); // 删除pid文件 @unlink(PID_FILE); exit(0); } } //end if } //end while }