/// <summary> /// 连接容器内部方法,子类可以重写此方法。 /// <para>*此方法主要用于确保在使用指定算法获取容器中连接之前,连接容器内部拥有足够多的连接</para> /// <para>*具体策略为优先保证在同步执行代码的情况下,当前连接容器中最少有一个存活的连接,至于剩下的连接需要异步进行创建</para> /// </summary> protected virtual bool MakeSureConnections() { if (_connections.Count >= _min || _connections.Count == 1) { return(true); } lock (_lockObj) { try { IServerConnectionAgent <T> agent = _createFunc(_tuple.Item1, _tuple.Item2, _tuple.Item3); //如果当前时间点无法正常创建一个连接代理器,则放弃此次同步机会并改为异步进行 if (agent == null || !agent.GetChannel().IsConnected) { return(false); } Register(agent); return(true); } catch (System.Exception ex) { _tracing.Error(ex); return(false); } finally { if (_connections.Count < _max && Interlocked.CompareExchange(ref _usedBackendThread, 1, 0) == 0) { CreateAgentAsync(); } } } }
/// <summary> /// 根据当前负载器规则获取一个通信信道 /// </summary> /// <param name="target">标示网络终点接的协议簇组合</param> /// <param name="level">KAE应用等级</param> /// <param name="protocolStack">协议栈</param> /// <param name="errMsg">错误信息</param> /// <param name="selectedRingNode">已选中的一致性HASH圆环节点</param> /// <returns>如果指定条件的通信信道不存在,则会创建它并返回</returns> /// <exception cref="ArgumentNullException">参数不能为空</exception> public IServerConnectionAgent <TMessage> GetChannel(Protocols target, ApplicationLevel level, IProtocolStack protocolStack, out string errMsg, out KAERingNode selectedRingNode) { lock (_lockObj) { IDictionary <ApplicationLevel, IDictionary <ProtocolTypes, KetamaRing> > firstLevel; if (_addresses.TryGetValue(target, out firstLevel)) { IDictionary <ProtocolTypes, KetamaRing> secondLevel; if (firstLevel.TryGetValue(level, out secondLevel)) { KetamaRing ring; if (secondLevel.TryGetValue(_protocolType, out ring)) { if (ring == null) { errMsg = string.Format("#Sadly, We have no more network information about what you gave of protocol: {0}-{1}-{2}, Maybe it was been removed or there wasn't any available network resources.", target.ProtocolId, target.ServiceId, target.DetailsId); selectedRingNode = null; return(null); } KAERingNode node = ring.GetWorkerNode(); IServerConnectionAgent <TMessage> agent = _connectionPool.GetChannel(node.EndPoint, node.RawAddress, protocolStack, _transactionManager); errMsg = (agent != null ? string.Empty : "#Sadly, We cannot connect to remote endpoint: " + node.RawAddress); selectedRingNode = node; return(agent); } } } errMsg = string.Format("#Couldn't find any remoting address which it can access it. #Protocol: {0}, #Level: {1}", target, level); selectedRingNode = null; return(null); } }
//agent disconnect event handler. private void ServerAgentDisconnected(object sender, System.EventArgs e) { IServerConnectionAgent <T> agent = (IServerConnectionAgent <T>)sender; agent.Disconnected -= ServerAgentDisconnected; lock (_lockObj) _connections.Remove(agent); AgentDisconnectedHandler(new LightSingleArgEventArgs <IServerConnectionAgent <T> >(agent)); }
void Disconnected(object sender, System.EventArgs e) { IServerConnectionAgent <BaseMessage> agent = (IServerConnectionAgent <BaseMessage>)sender; agent.Disconnected -= Disconnected; agent.NewTransaction -= NewTransaction; lock (_lockObj) _agents.Remove(agent); }
/// <summary> /// 注册一个连接代理器 /// </summary> /// <param name="agent">连接代理器</param> /// <exception cref="ArgumentNullException">参数不能为空</exception> public void Regist(IServerConnectionAgent <BaseMessage> agent) { if (agent == null) { throw new ArgumentNullException(nameof(agent)); } lock (_lockObj) _agents.Add(agent); agent.Disconnected += Disconnected; agent.NewTransaction += NewTransaction; }
/// <summary> /// 创建一个新的事务 /// </summary> /// <param name="role">针对的服务角色</param> /// <param name="userId">需要定位的用户编号</param> /// <returns>返回新的事务</returns> /// <exception cref="ArgumentNullException">参数不能为空</exception> public BusinessMessageTransaction CreateTransaction(string role, int userId) { if (string.IsNullOrEmpty(role)) { throw new ArgumentNullException("role"); } string errMsg; IServerConnectionAgent <BaseMessage> agent = _clsuter.GetChannelBySpecificCondition(role, _protocolStacks[role], userId, out errMsg); return(agent == null ? new FailMobiSageMessageTransaction(errMsg) : _transactionManager.Create(IdentityHelper.Create((IPEndPoint)agent.GetChannel().LocalEndPoint), agent.GetChannel())); }
/// <summary> /// 创建一个新的事务 /// </summary> /// <param name="role">针对的服务角色</param> /// <returns>返回新的事务</returns> /// <exception cref="ArgumentNullException">参数不能为空</exception> public MetadataMessageTransaction CreateMetadataTransaction(string role) { if (string.IsNullOrEmpty(role)) { throw new ArgumentNullException("role"); } string errMsg; IServerConnectionAgent <MetadataContainer> agent = _metadataCluster.GetChannel(role, _metadataProtocolStack, out errMsg); return(agent == null ? new FailMobiSageMetadataTransaction(errMsg) : _metadataTransactionManager.Create(IdentityHelper.Create((IPEndPoint)agent.GetChannel().LocalEndPoint), agent.GetChannel())); }
/// <summary> /// 向当前的连接容器中注册一个存活的连接 /// </summary> /// <param name="agent"></param> public virtual void Register(IServerConnectionAgent <T> agent) { if (agent == null) { return; } if (!agent.GetChannel().IsConnected) { AgentDisconnectedHandler(new LightSingleArgEventArgs <IServerConnectionAgent <T> >(agent)); return; } agent.Disconnected += ServerAgentDisconnected; lock (_lockObj) _connections.Add(agent); }
/// <summary> /// 创建一个新的单向通信事务 /// <para>* 使用此函数创建的事务是单向通信的,也就意味着新的事务不会触发RecvRsp事件</para> /// </summary> /// <param name="role">针对的服务角色</param> /// <returns>返回新的事务</returns> /// <exception cref="ArgumentNullException">参数不能为空</exception> public BusinessMessageTransaction CreateOnewayTransaction(string role) { if (string.IsNullOrEmpty(role)) { throw new ArgumentNullException("role"); } string errMsg; IServerConnectionAgent <BaseMessage> agent = _clsuter.GetChannel(role, _protocolStacks[role], out errMsg); return(agent == null ? new FailMobiSageMessageTransaction(errMsg) : new BusinessMessageTransaction(new Lease(DateTime.MaxValue), agent.GetChannel()) { Identity = IdentityHelper.CreateOneway((IPEndPoint)agent.GetChannel().LocalEndPoint) }); }
/// <summary> /// 创建一个新的事务 /// <para>* 按照固定手机号的负载策略</para> /// </summary> /// <param name="targetRole">针对的服务角色</param> /// <param name="protocolSelf">使用的协议栈</param> /// <param name="mobileNo">手机号</param> /// <returns>返回新的事务</returns> /// <exception cref="ArgumentNullException">参数不能为空</exception> public BusinessMessageTransaction CreateTransaction(string targetRole, string protocolSelf, long mobileNo) { if (string.IsNullOrEmpty(targetRole)) { throw new ArgumentNullException("targetRole"); } if (string.IsNullOrEmpty(protocolSelf)) { throw new ArgumentNullException("protocolSelf"); } string errMsg; IServerConnectionAgent <BaseMessage> agent = _clsuter.GetChannelBySpecificCondition(targetRole, _protocolStacks[protocolSelf], mobileNo, out errMsg); return(agent == null ? new FailMobiSageMessageTransaction(errMsg) : _transactionManager.Create(IdentityHelper.Create((IPEndPoint)agent.GetChannel().LocalEndPoint), agent.GetChannel())); }
/// <summary> /// 创建一个新的单向通信事务 /// <para>* 使用此函数创建的事务是单向通信的,也就意味着新的事务不会触发RecvRsp事件</para> /// </summary> /// <param name="targetRole">针对的服务角色</param> /// <param name="protocolSelf">使用的协议栈</param> /// <param name="userId">需要定位的用户编号</param> /// <returns>返回新的事务</returns> /// <exception cref="ArgumentNullException">参数不能为空</exception> public BusinessMessageTransaction CreateOnewayTransaction(string targetRole, string protocolSelf, int userId) { if (string.IsNullOrEmpty(targetRole)) { throw new ArgumentNullException("targetRole"); } if (string.IsNullOrEmpty(protocolSelf)) { throw new ArgumentNullException("protocolSelf"); } string errMsg; IServerConnectionAgent <BaseMessage> agent = _clsuter.GetChannelBySpecificCondition(protocolSelf, _protocolStacks[protocolSelf], userId, out errMsg); return(agent == null ? new FailMobiSageMessageTransaction(errMsg) : new BusinessMessageTransaction(new Lease(DateTime.MaxValue), agent.GetChannel()) { Identity = IdentityHelper.CreateOneway((IPEndPoint)agent.GetChannel().LocalEndPoint) }); }
/// <summary> /// 使用后台线程的方式异步地创建连接代理器 /// </summary> private void CreateAgentAsync() { if (_backendThread != null) { return; } _backendThread = new Thread(delegate() { int retryCount = 0; while (_connections.Count < _max) { try { IServerConnectionAgent <T> agent = _createFunc(_tuple.Item1, _tuple.Item2, _tuple.Item3); //如果当前时间点无法正常创建一个连接代理器,则默认行为是重试3次 if (agent == null || !agent.GetChannel().IsConnected) { if (retryCount < 3) { retryCount++; continue; } Interlocked.Exchange(ref _usedBackendThread, 0); _backendThread = null; break; } //reset retry counter. retryCount = 0; Register(agent); } catch (System.Exception ex) { _tracing.Error(ex); } } Interlocked.Exchange(ref _usedBackendThread, 0); _backendThread = null; }) { IsBackground = true, Name = "ConnectionSet-Backend-Thread" }; _backendThread.Start(); }
/// <summary> /// 创建一个新的网络事务 /// </summary> /// <param name="appName">目标APP的名称</param> /// <param name="target">标示网络终点接的协议簇组合</param> /// <param name="maximumRspTime">等待当前网络事务RSP消息的最大时间</param> /// <param name="resourceUri">KAE资源URI</param> /// <param name="balanceFlag">负载标识</param> /// <param name="communicationType">通信方式</param> /// <param name="version"> /// 目标APP的版本 /// <para>* 默认为: latest</para> /// </param> /// <param name="protocolSelf"> /// 使用的协议栈的角色 /// <para>* 如果当前事务代理器所承载的消息协议为MetadataContainer时请忽略此参数</para> /// </param> /// <returns>返回新的事务</returns> public IMessageTransaction <TMessage> CreateTransaction(string appName, Protocols target, TimeSpan maximumRspTime, long balanceFlag, string version = "latest", KAEResourceUri resourceUri = null, NetworkCommunicationTypes communicationType = NetworkCommunicationTypes.Dulplex, string protocolSelf = null) { if (string.IsNullOrEmpty(appName)) { throw new ArgumentNullException("appName"); } string errMsg; ApplicationLevel level = (resourceUri == null ? ApplicationLevel.Stable : _callback(resourceUri)); KAERingNode ringNode; IServerConnectionAgent <TMessage> agent = _cluster.GetChannel(target, level, _container.GetDefaultProtocolStack(_cluster.ProtocolType), balanceFlag, out errMsg, out ringNode); if (agent == null) { lock (_lockObj) { //try to obtains agent object again for ensuring that the newest remoting addresses can be appliy in the multiple threading env. agent = _cluster.GetChannel(target, level, _container.GetDefaultProtocolStack(_cluster.ProtocolType), balanceFlag, out errMsg, out ringNode); if (agent == null && !GetMissedRemoteAddresses(appName, version, target, level)) { return(new FailMessageTransaction <TMessage>(errMsg)); } agent = _cluster.GetChannel(target, level, _container.GetDefaultProtocolStack(_cluster.ProtocolType), balanceFlag, out errMsg, out ringNode); //check returned value again for avoiding couldnt connect to the remote address now. if (agent == null) { return(new FailMessageTransaction <TMessage>(errMsg)); } } } MessageTransaction <TMessage> transaction = NewTransaction(new Lease(DateTime.Now.Add(maximumRspTime)), agent.GetChannel()); transaction.SetMessageIdentity(new MessageIdentity { ProtocolId = (byte)target.ProtocolId, ServiceId = (byte)target.ServiceId, DetailsId = (byte)target.DetailsId }); transaction.TransactionManager = _transactionManager; transaction.Identity = (communicationType == NetworkCommunicationTypes.Dulplex ? IdentityHelper.Create(agent.GetChannel().LocalEndPoint, TransportChannelTypes.TCP) : IdentityHelper.CreateOneway(agent.GetChannel().LocalEndPoint, TransportChannelTypes.TCP)); transaction.KPPUniqueId = ringNode.KPPUniqueId; return(_transactionManager.Add(transaction.Identity, transaction) ? transaction : null); }