接着上面一篇我们分析正常请求的处理过程。
private function requestProcessor($client_id, $request)
{
//开始执行时间
$request->startTime = microtime(true);
//监控请求数量
$this->server->getAppMonitor()->onRequest($request);
//设置traceContext, 增加本地的IP地址及APP的端口
$appConfig = $this->getAppConfig();
$localIP = FSOFSystemUtil::getLocalIP();
$appPort = $appConfig['server']['listen'][0];
$params = $request->__toString();
if (mb_strlen($params, 'UTF-8') >= 512)
{
$params = mb_substr($params, 0, 512, 'UTF-8').' ...';
}
$this->logger->debug("in|".$params);
$businessError = false;
$frameError = false;
$result = null;
//业务处理状态
$requestFlag = false;
//返回给客户端执行结果信息
//$errMsg = 'ok'; //异常信息
//消息在队列等待时间
$wait_InQueueTime = 0;
$inQueueTime = DubboParser::getReqInQueueTime($request);
if($inQueueTime)
{
$wait_InQueueTime = round(microtime(true)*1000000) - $inQueueTime;
}
//处理前先检测连接是否仍正常,如己断开则不进行处理
if(!$this->swoole_server->exist($client_id))
{
//执行结束时间
$request->endTime = microtime(true);
$cost_time = (int)(($request->endTime - $request->startTime)* 1000000);
goto END_TCP_CLOSE;
}
//检测服务状态信息,这里主要检查是否过载
$status = $this->checkSwooleStatus($request, $localIP, $appPort);
if(self::FSOF_SWOOLE_STATUS_OK == $status)//服务正常,也就是没过载
{
//当前app是否提供了满足条件的服务
if($this->server->serviceExist($request->getService(), $request->getGroup(), $request->getVersion()))
{
//获取app中满足条件的服务实例,一个app提供的所有服务都以单实例的形式存于内存中
$serviceInstance = $this->server->getServiceInstance($request->getService(), $request->getGroup(), $request->getVersion());
if (null != $serviceInstance)
{
try
{
//调用PHP的反射接口反射服务实例
$serviceReflection = new \ReflectionObject($serviceInstance);
//判断服务实例中是否存在请求的方法
if ($serviceReflection->hasMethod($request->getMethod()))
{
//获取方法对象
$method = $serviceReflection->getmethod($request->getMethod());
//允许invoke protected方法
$method->setAccessible(true);
//获取请求方法参数信息
$params = $request->getParams();
if($params == NULL)//如果没有参数信息,转成空数组,这里应该是为了业务处理统一。
{
$params = array();
}
//执行反射回调
$result = $method->invokeArgs($serviceInstance, $params);
$requestFlag = true;
}
else//服务实例不存在请求方法信息,抛出业务报错。
{
$businessError = true;
$result = 'function not found:'.$request->getMethod().' in '.$request->getService();
$this->logger->error("[{$request->getMethod()}] function not found:".$request->getService());
}
}
catch (\Exception $e)//捕捉执行过程中的所有异常,记录为框架异常。
{
$this->logger->error($e);
$frameError = true;
$result = $e->getMessage().' in '.$e->getFile().'|'.$e->getLine();
}
//如果provider service有状态,则$serviceInstance用完后unset,下次请求重新new, 防止内存泄漏; 对于无状态的service,AppContext会复用$serviceInstance
if (!$this->server->isStateless())
{
unset($serviceInstance);
}
unset($method);
unset($serviceReflection);
}
else//反射服务实例失败,记录为框架错误。
{
$frameError = true;
$result ='get instance failed! | '.$request->getService();
$this->logger->error(json_encode($result));
}
}
else//服务实例不存在,记录为框架错误。
{
$frameError = true;
$result = 'service not found:'.$request->getGroup()."/".$request->getService().":".$request->getVersion();
$this->logger->error(json_encode($result));
}
}
else //服务实例过载
{
$frameError = true;
$result = 'provider过载, 请求消息在队列等待时间超过阀值';
}
$request->endTime = microtime(true);//执行结束时间
$cost_time = (int)(($request->endTime - $request->startTime)* 1000000);
//判断swoole是否还保持着这个客服端连接
if($this->swoole_server->exist($client_id))
{
//发送response
$response = $this->packResponse($client_id, $request, $result, $businessError,$frameError);
$msg = $response->__toString();
if (mb_strlen($msg, 'UTF-8') >= 512)
{
$msg = mb_substr($msg, 0, 512, 'UTF-8').' ...('.strlen($msg).')';
}
$this->logger->debug(sprintf("out|%s|invokeCostTime:%dus|waitInQueueTime:%dus", $msg, $cost_time, $wait_InQueueTime));
}
else //swoole已经不保持这个链接,这时候只是记录日志,已经没法给客户端回复错误信息了。
{
END_TCP_CLOSE:
$errMsg = "socket closed by consumer, provider discard response data";
$this->logger->error("out|{$errMsg}|invokeCostTime:{$cost_time}us| waitInQueueTime:{$wait_InQueueTime}us");
$requestFlag = false;
}
if($requestFlag)
{
//监控请求正常处理数量
$this->server->getAppMonitor()->onResponse($request);
}
else
{
//监控请求错误处理数量
$this->server->getAppMonitor()->onError($request);
}
}
//服务实例上下文管理
final class AppContext
{
private $instances = array();
private $stateless = FALSE;//默认所有服务都是有状态的,每次使用都重新new
private $server;
public function setStateless($stateless, $server)
{
$this->stateless = $stateless;
$this->server = $server;
}
public function isStateless()
{
return $this->stateless;
}
public function getInstance($className, $params = null)
{
if($this->stateless) //服务是有状态的,除了首次new之外,其他的都通过内存缓存,后续不再重复new。
{
\Logger::getLogger(__CLASS__)->debug("get stateless instance for $className");
if (isset($this->instances[$className]))
{
return $this->instances[$className];
}
if (!class_exists($className,true))
{
throw new \Exception("no class {$className}");
}
if (empty($params))
{
$this->instances[$className] = new $className();
}
else
{
$this->instances[$className] = new $className($params);
}
return $this->instances[$className];
}
else //服务实例是无状态的,每次都是直接new新的服务实例
{
\Logger::getLogger(__CLASS__)->debug("get new instance for $className");
if (!class_exists($className,true))
{
throw new \Exception("no class {$className}");
}
if (empty($params))
{
return new $className();
}
else
{
return new $className($params);
}
}
}
}