Repository: multilinguals/apollo-php-client Branch: master Commit: 497dd462549a Files: 7 Total size: 11.8 KB Directory structure: gitextract_jsdxusry/ ├── .gitignore ├── README.md ├── composer.json ├── examples/ │ └── laravel/ │ ├── README.md │ ├── apollo.php │ └── env/ │ └── .env_tpl.php └── src/ └── ApolloClient.php ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # Created by .ignore support plugin (hsz.mobi) .idea apolloConfig.* test.php vendor ================================================ FILE: README.md ================================================ # [携程Apollo](https://github.com/ctripcorp/apollo)的PHP客户端 ## install php version >= 7.0 ```bash $ composer require multilinguals/apollo-client ``` php version >= 5.4 , <7.0 ```bash $ composer require multilinguals/apollo-client --ignore-platform-reqs ``` ## Features - 支持apollo配置变更的实时获取 - 支持拉取配置后自定义的回调处理 ## Usage 客户端以cli的方式后台启动执行,支持apollo配置的适时获取,并将配置保存在指定的目录供应用程序读取解析 ### 客户端示例代码 ```php #!/usr/bin/env php setClientIp($clientIp); } ini_set('memory_limit','128M'); $pid = getmypid(); echo "start [$pid]\n"; $restart = true; //auto start if failed do { $error = $apollo->start(); if ($error) echo('error:'.$error."\n"); }while($error && $restart); ``` ### 配置管理 拉取的配置默认保存在脚本所在目录,每个namespace的配置以`apolloConfig.{$namespaceName}.php`的方式命名保存 ### Docker环境客户端自启动 在docker的启动脚本中加入启动代码,一般的php容器启动脚本是docker-php-entrypoint ```bash if [ -f "/path/to/start.php" ]; then apollo_ps=$(ps -aux | grep -c "php /path/to/start.php") if [ $apollo_ps -eq 1 ]; then php /path/to/start.php & fi fi ``` ================================================ FILE: composer.json ================================================ { "name": "multilinguals/apollo-client", "description": "apollo client for php", "type": "library", "license": "MIT", "keywords": [ "Apollo", "Client" ], "homepage": "https://github.com/multilinguals/apollo-php-client", "require": { "php": "~7.0" }, "autoload": { "psr-4": { "Org\\Multilinguals\\Apollo\\Client\\": "src/" } } } ================================================ FILE: examples/laravel/README.md ================================================ ### apollo client for laravel #### 启动apollo客户端 php apollo.php ================================================ FILE: examples/laravel/apollo.php ================================================ #!/usr/bin/env php setClientIp($clientIp); * } */ //从apollo上拉取的配置默认保存在脚本目录,可自行设置保存目录 $apollo->save_dir = SAVE_DIR; ini_set('memory_limit','128M'); $pid = getmypid(); echo "start [$pid]\n"; $restart = false; //失败自动重启 do { $error = $apollo->start($callback); //此处传入回调 if ($error) echo('error:'.$error."\n"); }while($error && $restart); ================================================ FILE: examples/laravel/env/.env_tpl.php ================================================ configServer = $configServer; $this->appId = $appId; foreach ($namespaces as $namespace) { $this->notifications[$namespace] = ['namespaceName' => $namespace, 'notificationId' => -1]; } $this->save_dir = dirname($_SERVER['SCRIPT_FILENAME']); } public function setCluster($cluster) { $this->cluster = $cluster; } public function setClientIp($ip) { $this->clientIp = $ip; } public function setPullTimeout($pullTimeout) { $pullTimeout = intval($pullTimeout); if ($pullTimeout < 1 || $pullTimeout > 300) { return; } $this->pullTimeout = $pullTimeout; } public function setIntervalTimeout($intervalTimeout) { $intervalTimeout = intval($intervalTimeout); if ($intervalTimeout < 1 || $intervalTimeout > 300) { return; } $this->intervalTimeout = $intervalTimeout; } private function _getReleaseKey($config_file) { $releaseKey = ''; if (file_exists($config_file)) { $last_config = require $config_file; is_array($last_config) && isset($last_config['releaseKey']) && $releaseKey = $last_config['releaseKey']; } return $releaseKey; } //获取单个namespace的配置文件路径 public function getConfigFile($namespaceName) { return $this->save_dir.DIRECTORY_SEPARATOR.'apolloConfig.'.$namespaceName.'.php'; } //获取单个namespace的配置-无缓存的方式 public function pullConfig($namespaceName) { $base_api = rtrim($this->configServer, '/').'/configs/'.$this->appId.'/'.$this->cluster.'/'; $api = $base_api.$namespaceName; $args = []; $args['ip'] = $this->clientIp; $config_file = $this->getConfigFile($namespaceName); $args['releaseKey'] = $this->_getReleaseKey($config_file); $api .= '?' . http_build_query($args); $ch = curl_init($api); curl_setopt($ch, CURLOPT_TIMEOUT, $this->pullTimeout); curl_setopt($ch, CURLOPT_HEADER, false); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $body = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $error = curl_error($ch); curl_close($ch); if ($httpCode == 200) { $result = json_decode($body, true); $content = 'configServer, '/').'/configs/'.$this->appId.'/'.$this->cluster.'/'; $query_args = []; $query_args['ip'] = $this->clientIp; foreach ($namespaceNames as $namespaceName) { $request = []; $config_file = $this->getConfigFile($namespaceName); $request_url = $base_url.$namespaceName; $query_args['releaseKey'] = $this->_getReleaseKey($config_file); $query_string = '?'.http_build_query($query_args); $request_url .= $query_string; $ch = curl_init($request_url); curl_setopt($ch, CURLOPT_TIMEOUT, $this->pullTimeout); curl_setopt($ch, CURLOPT_HEADER, false); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $request['ch'] = $ch; $request['config_file'] = $config_file; $request_list[$namespaceName] = $request; curl_multi_add_handle($multi_ch, $ch); } $active = null; // 执行批处理句柄 do { $mrc = curl_multi_exec($multi_ch, $active); } while ($mrc == CURLM_CALL_MULTI_PERFORM); while ($active && $mrc == CURLM_OK) { if (curl_multi_select($multi_ch) == -1) { usleep(100); } do { $mrc = curl_multi_exec($multi_ch, $active); } while ($mrc == CURLM_CALL_MULTI_PERFORM); } // 获取结果 $response_list = []; foreach ($request_list as $namespaceName => $req) { $response_list[$namespaceName] = true; $result = curl_multi_getcontent($req['ch']); $code = curl_getinfo($req['ch'], CURLINFO_HTTP_CODE); $error = curl_error($req['ch']); curl_multi_remove_handle($multi_ch,$req['ch']); curl_close($req['ch']); if ($code == 200) { $result = json_decode($result, true); $content = 'configServer, '/').'/notifications/v2?'; $params = []; $params['appId'] = $this->appId; $params['cluster'] = $this->cluster; do { $params['notifications'] = json_encode(array_values($this->notifications)); $query = http_build_query($params); curl_setopt($ch, CURLOPT_URL, $base_url.$query); $response = curl_exec($ch); $httpCode = curl_getinfo($ch,CURLINFO_HTTP_CODE); $error = curl_error($ch); if ($httpCode == 200) { $res = json_decode($response, true); $change_list = []; foreach ($res as $r) { if ($r['notificationId'] != $this->notifications[$r['namespaceName']]['notificationId']) { $change_list[$r['namespaceName']] = $r['notificationId']; } } $response_list = $this->pullConfigBatch(array_keys($change_list)); foreach ($response_list as $namespaceName => $result) { $result && ($this->notifications[$namespaceName]['notificationId'] = $change_list[$namespaceName]); } //如果定义了配置变更的回调,比如重新整合配置,则执行回调 ($callback instanceof \Closure) && call_user_func($callback); }elseif ($httpCode != 304) { throw new \Exception($response ?: $error); } }while (true); } /** * @param $callback 监听到配置变更时的回调处理 * @return mixed */ public function start($callback = null) { $ch = curl_init(); curl_setopt($ch, CURLOPT_TIMEOUT, $this->intervalTimeout); curl_setopt($ch, CURLOPT_HEADER, false); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); try { $this->_listenChange($ch, $callback); }catch (\Exception $e) { curl_close($ch); return $e->getMessage(); } } }