/** * 该worker进程开始服务的时候会触发一次 * @return bool */ protected function onServe() { // 文件更新相关 mac不支持inotify 用这个进程监控 500ms检测一次 if (!Inotify::isSuport() && PHPServerConfig::get('ENV') == 'dev') { $this->eventLoopName = 'Select'; // 安装信号处理函数 $this->installSignal(); $this->event = new $this->eventLoopName(); if ($this->protocol == 'udp') { // 添加读udp事件 $this->event->add($this->mainSocket, BaseEvent::EV_ACCEPT, array($this, 'recvUdp')); } else { // 添加accept事件 $this->event->add($this->mainSocket, BaseEvent::EV_ACCEPT, array($this, 'accept')); } // 添加管道可读事件 $this->event->add($this->channel, BaseEvent::EV_READ, array($this, 'dealCmd'), 0, 0); // 增加select超时事件 $this->event->add(0, Select::EV_SELECT_TIMEOUT, array($this, 'checkFilesModify'), array(), 500); // 主体循环 while (1) { $ret = $this->event->loop(); $this->notice("evet->loop returned " . var_export($ret, true)); } return true; } }
/** * 上报包含文件到监控进程 * @param array $files */ public static function reportIncludedFiles($worker_files_map) { //非开发环境或者安装了inotify扩展直接返回 if (PHPServerConfig::get('ENV') !== 'dev' || Inotify::isSuport()) { return; } if ($worker_files_map && is_array($worker_files_map)) { $files = array(); foreach ($worker_files_map as $worker_name => $files_array) { foreach ($files_array as $file) { $files[$file] = $file; } } if ($files) { return self::sendData(self::CMD_TELL_INCLUDE_FILES, array_values($files)); } } }
/** * 处理命令 * @param char $cmd * @param mix $result * @param int $pid */ protected static function dealCmd($cmd, $result, $pid) { // 获得所有pid到worker_name映射关系 $all_pid_and_worker = self::getPidWorkerNameMap(); $worker_name = isset($all_pid_and_worker[$pid]) ? $all_pid_and_worker[$pid] : ''; switch ($cmd) { // 监控worker的使用的文件 case Cmd::CMD_REPORT_INCLUDE_FILE: if (is_array($result)) { if (empty($worker_name)) { self::notice("CMD_REPORT_INCLUDE_FILE pid:{$pid} has no worker_name"); return false; } // 获取已经监控的文件 $all_inotify_files = self::getFilesWorkerNameMap(); // 获取master进程使用的文件 $master_included_files = array_flip(get_included_files()); // 遍历worker上报的包含文件 foreach ($result as $file) { // 过滤master进程包含的文件,没有监控的文件加入监控 if (!isset($all_inotify_files[$file]) && !isset($master_included_files[$file])) { self::$filesToInotify[$worker_name][$file] = $file; if (Inotify::isSuport()) { Inotify::addFile($file); } } } return true; } break; // 停止服务 // 停止服务 case Cmd::CMD_STOP_SERVE: // self::$event->delAll(self::$channels[$pid]); break; // 测试命令 // 测试命令 case Cmd::CMD_TEST: break; // 重启命令 // 重启命令 case Cmd::CMD_RESTART: // self::$event->delAll(self::$channels[$pid]); break; // telnet报告worker状态 // telnet报告worker状态 case Cmd::CMD_REPORT_STATUS_FOR_MASTER: $workers = PHPServerConfig::get('workers'); $port = isset($workers[$worker_name]['port']) ? $workers[$worker_name]['port'] : 'none'; $proto = isset($workers[$worker_name]['protocol']) ? $workers[$worker_name]['protocol'] : 'none'; $str = "{$pid}\t" . str_pad(round($result['memory'] / (1024 * 1024), 2) . "M", 9) . " {$proto} " . str_pad($port, 5) . " " . $result['start_time'] . " " . str_pad($worker_name, self::$maxWorkerNameLength) . " "; if ($result) { $str = $str . str_pad($result['total_request'], 14) . " " . str_pad($result['recv_timeout'], 12) . " " . str_pad($result['proc_timeout'], 12) . " " . str_pad($result['packet_err'], 10) . " " . str_pad($result['thunder_herd'], 12) . " " . str_pad($result['client_close'], 12) . " " . str_pad($result['send_fail'], 9) . " " . str_pad($result['throw_exception'], 15) . " " . ($result['total_request'] == 0 ? 100 : round(($result['total_request'] - ($result['proc_timeout'] + $result['packet_err'] + $result['send_fail'])) / $result['total_request'], 6) * 100) . "%"; } else { $str .= var_export($result, true); } Telnet::sendToClient($str . "\n"); break; // 心跳包回复 // 心跳包回复 case Cmd::CMD_PONG: self::$pingInfo[$pid] = 0; break; // 未知命令 // 未知命令 case Cmd::CMD_UNKNOW: break; } }