/** * 从消息队列中获取要监控的文件列表 * @param bool $block * @return void */ protected function collectFiles($block = false) { $msg_type = $message = null; $flag = $block ? 0 : MSG_IPC_NOWAIT; if (@msg_receive(\Man\Core\Master::getQueueId(), self::MSG_TYPE_FILE_MONITOR, $msg_type, 10000, $message, true, $flag)) { // 被排除的路径 $exclude_path = array(); // 因为配置可能会被更改,所以每次都会重新从配置中查找排除路径 $config_exclude_path = $this->getExcludeFiles(); foreach ($config_exclude_path as $path) { if ($real_path = realpath($path)) { $exclude_path[] = $real_path; } } foreach ($message as $file) { $is_exclude_file = false; foreach ($exclude_path as $path) { // 是被排除的文件 if (0 === strpos($file, $path)) { $is_exclude_file = true; break; } } if (!$is_exclude_file && !isset($this->filesToInotify[$file])) { $stat = @stat($file); $mtime = isset($stat['mtime']) ? $stat['mtime'] : 0; $this->filesToInotify[$file] = $mtime; } } } }
/** * 从消息队列中获取要监控的文件列表 * @param bool $block * @return void */ protected function collectFiles($block = false) { $msg_type = $message = null; $flag = $block ? 0 : MSG_IPC_NOWAIT; if (msg_receive(\Man\Core\Master::getQueueId(), self::MSG_TYPE_FILE_MONITOR, $msg_type, 10000, $message, true, $flag)) { foreach ($message as $file) { if (!isset($this->filesToInotify[$file])) { $stat = @stat($file); $mtime = isset($stat['mtime']) ? $stat['mtime'] : 0; $this->filesToInotify[$file] = $mtime; } } } }
/** * 开发环境将当前进程使用的文件写入消息队列,用于FileMonitor监控文件更新 * @return void */ protected function writeFilesListToQueue() { if (!Master::getQueueId()) { return; } $error_code = 0; $flip_file_list = array_flip(get_included_files()); $file_list = array_diff_key($flip_file_list, $this->includeFiles); $this->includeFiles = $flip_file_list; if ($file_list) { foreach (array_chunk($file_list, 10, true) as $list) { msg_send(Master::getQueueId(), self::MSG_TYPE_FILE_MONITOR, array_keys($list), true, false, $error_code); } } }
/** * 检测主进程是否存在 * @return void */ public function checkMasterProcess() { $master_pid = \Man\Core\Master::getMasterPid(); if (!posix_kill($master_pid, 0)) { $this->onMasterDead(); } }
/** * 检查配置的pid文件是否可写 * @return void */ public static function checkPidFile() { // 已经有进程pid可能server已经启动 if (@file_get_contents(WORKERMAN_PID_FILE)) { \Man\Core\Master::notice("[33;40mWorkerman already started[0m", true); exit; } if (is_dir(WORKERMAN_PID_FILE)) { exit("\n[31;40mpid-file " . WORKERMAN_PID_FILE . " is Directory[0m\n\n[31;40mWorkerman start failed[0m\n\n"); } $pid_dir = dirname(WORKERMAN_PID_FILE); if (!is_dir($pid_dir)) { if (!mkdir($pid_dir, 0777, true)) { exit("Create dir {$pid_dir} fail\n"); } } if (!is_writeable($pid_dir)) { exit("\n[31;40m{$pid_dir} is not writeable, can't write pid file[0m\n\n[31;40mWorkerman start failed[0m\n\n"); } }
/** * 检查配置的pid文件是否可写 * @return void */ public static function checkPidFile() { // 已经有进程pid可能server已经启动 if (@file_get_contents(WORKERMAN_PID_FILE)) { \Man\Core\Master::notice("Server already started", true); exit; } if (is_dir(WORKERMAN_PID_FILE)) { exit("\n[31;40mpid-file " . WORKERMAN_PID_FILE . " is Directory[0m\n\n[31;40mServer start failed[0m\n\n"); } $pid_dir = dirname(WORKERMAN_PID_FILE); if (!is_dir($pid_dir)) { if (!mkdir($pid_dir, true)) { exit("Create dir {$pid_dir} fail\n"); } } if (!is_writeable($pid_dir)) { exit("\n[31;40mYou should start the server as root[0m\n\n[31;40mServer start failed[0m\n\n"); } }
/** * 关闭标准输入输出 * @return void */ protected function resetFd() { if (\Man\Core\Master::hasResetFd()) { return; } global $STDOUT, $STDERR; @fclose(STDOUT); @fclose(STDERR); $STDOUT = fopen('/dev/null', "a"); $STDERR = fopen('/dev/null', "a"); }
/** * 获取主进程统计信息 * @return array */ protected function getMasterStatus() { if (!Master::getShmId()) { return array(); } return @shm_get_var(Master::getShmId(), Master::STATUS_VAR_ID); }
/** * 检查worker配置、worker语法错误等 * @return void */ public static function checkWorkersConfig() { foreach (Config::getAllWorkers() as $worker_name => $config) { if (strlen($worker_name) > self::$maxWorkerNameLength) { self::$maxWorkerNameLength = strlen($worker_name); } if (isset($config['user']) && strlen($config['user']) > self::$maxUserNameLength) { self::$maxUserNameLength = strlen($config['user']); } if (isset($config['listen']) && strlen($config['listen']) > self::$maxListenLength) { self::$maxListenLength = strlen($config['listen']); } } $total_worker_count = 0; // 检查worker echo "------------------------ WORKERS -------------------------------\n"; echo "worker", str_pad('', self::$maxWorkerNameLength + 2 - strlen('worker')), "listen", str_pad('', self::$maxListenLength + 2 - strlen('listen')), "processes", str_pad('', self::$maxProcessCountLength + 2 - strlen('processes')), "", "status\n"; foreach (Config::getAllWorkers() as $worker_name => $config) { echo str_pad($worker_name, self::$maxWorkerNameLength + 2); if (isset($config['listen'])) { echo str_pad($config['listen'], self::$maxListenLength + 2); } else { echo str_pad('none', self::$maxListenLength + 2); } if (empty($config['start_workers'])) { \Man\Core\Master::notice(str_pad($worker_name, 40) . " [start_workers not set]\tWorkerman start fail"); exit(str_pad('', self::$maxProcessCountLength + 2) . " [start_workers not set]\n\nWorkerman start fail\n"); } echo str_pad(' ' . $config['start_workers'], self::$maxProcessCountLength + 2); $total_worker_count += $config['start_workers']; // 语法检查 if (!($worker_file = \Man\Core\Lib\Config::get($worker_name . '.worker_file'))) { \Man\Core\Master::notice("{$worker_name} not set worker_file in conf/conf.d/{$worker_name}.conf"); echo " [not set worker_file] \n"; continue; } echo " [OK] \n"; } if ($total_worker_count > \Man\Core\Master::SERVER_MAX_WORKER_COUNT) { \Man\Core\Master::notice("Number of worker processes can not be greater than " . \Man\Core\Master::SERVER_MAX_WORKER_COUNT . ".\tPlease check start_workers in " . WORKERMAN_ROOT_DIR . "config/main.php\tWorkerman start fail"); exit("\nNumber of worker processes can not be greater than " . \Man\Core\Master::SERVER_MAX_WORKER_COUNT . ".\nPlease check start_workers in " . WORKERMAN_ROOT_DIR . "config/main.php\n\nWorkerman start fail\n"); } echo "----------------------------------------------------------------\n"; }
/** * 将当前worker进程状态写入消息队列 * @return void */ protected function writeStatusToQueue() { if (!Master::getQueueId()) { return; } $error_code = 0; @msg_send(Master::getQueueId(), self::MSG_TYPE_STATUS, array_merge($this->statusInfo, array('memory' => memory_get_usage(true), 'pid' => posix_getpid(), 'worker_name' => $this->workerName)), true, false, $error_code); }