【背景】
做一個thrift client的wrapper,用以實現對於伺服器的重試邏輯。
【關鍵點】
1. wrapper要求跟用client一樣方便。
2. 當某個伺服器掛掉之後可以隨機選另一台重試。
3. 用到的php幾個關鍵特性: __call()(magic function,當訪問的對象函數不存在時會調用這個), ReflectionClass 反射類及其其成員函數newInstanceArgs , call_user_func_array回呼函數。
直接看代碼吧(某位牛人寫的,not me):
#!/usr/bin/env php<?phpnamespace wrapper;error_reporting(E_ALL);require_once '/usr/local/Cellar/thrift/0.9.1/Thrift/ClassLoader/ThriftClassLoader.php';use Thrift\ClassLoader\ThriftClassLoader;$GEN_DIR = realpath(dirname(__FILE__).'/..').'/gen-php';$loader = new ThriftClassLoader();$loader->registerNamespace('Thrift', '/usr/local/Cellar/thrift/0.9.1/');$loader->registerDefinition('xiaoju', $GEN_DIR);$loader->register();use Thrift\Protocol\TBinaryProtocol;use Thrift\Transport\TSocket;use Thrift\Transport\THttpClient;use Thrift\Transport\TBufferedTransport;use Thrift\Exception\TException;class RetryWrapper { public function __construct($classname, $hosts) { $this->clazz = new \ReflectionClass($classname); $this->hosts = $hosts; } public function __call($method, $args) { shuffle($this->hosts); foreach ($this->hosts as $key => $host) { try { return $this->inner_call($host, $method, $args); } catch (TException $ex) { $msg = $ex->getMessage(); if (!strstr($msg, 'TSocket')) { throw $ex; } } } throw new TException("all server down!"); } public function inner_call($host, $method, $args) { $tmp = explode(":", $host); $socket = new TSocket($tmp[0], (int)$tmp[1]); $transport = new TBufferedTransport($socket, 1024, 1024); $protocol = new TBinaryProtocol($transport); $client = $this->clazz->newInstanceArgs(array($protocol)); $transport->open(); $result = call_user_func_array(array($client, $method), $args); $transport->close(); return $result; }}$hosts = array('localhost:9090', 'localhost:9091');$wrapper = new RetryWrapper("\xxx\xx\MessageServiceClient", $hosts, 3);$data = array('businessId' => 300100001, 'phones' => array('2','2','3'), 'message' => 'asdfqer') ;$message = new \xxx\xx\Message($data);print $wrapper->sendMessage($message);print "\n";?>
還是挺巧妙的,先記錄下來