【背景】
做一个thrift client的wrapper,用以实现对于服务器的重试逻辑。
【关键点】
1. wrapper要求跟用client一样方便。
2. 当某个服务器挂掉之后可以随机选另一台重试。
3. 用到的php几个关键特性: __call()(magic function,当访问的对象函数不存在时会调用这个), ReflectionClass 反射类及其其成员函数newInstanceArgs , call_user_func_array回调函数。
直接看代码吧(某位牛人写的,not me):
#!/usr/bin/env php
<?php
namespace 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";
?>
还是挺巧妙的,先记录下来