private Util.SchedulerTask Schedule(Service service, long sessionId, int millisecondsTimeout) { return(global::Zeze.Util.Scheduler.Instance.Schedule( (ThisTask) => { Rpc <TArgument, TResult> context = service.RemoveRpcContext <Rpc <TArgument, TResult> >(sessionId); if (null == context) // 一般来说,此时结果已经返回。 { return; } context.IsTimeout = true; context.ResultCode = Zeze.Transaction.Procedure.Timeout; if (null != context.Future) { context.Future.TrySetException(new RpcTimeoutException()); } else { this.ResponseHandle?.Invoke(context); } }, millisecondsTimeout, -1)); }
/// <summary> /// 异步发送rpc请求。 /// 1. 如果返回true,表示请求已经发送,并且建立好了上下文。 /// 2. 如果返回false,请求没有发送成功,上下文也没有保留。 /// </summary> /// <param name="so"></param> /// <param name="responseHandle"></param> /// <param name="millisecondsTimeout"></param> /// <returns></returns> public bool Send(AsyncSocket so, Func <Protocol, int> responseHandle, int millisecondsTimeout = 5000) { if (so == null || so.Service == null) { return(false); } this.IsRequest = true; this.ResponseHandle = responseHandle; this.Timeout = millisecondsTimeout; this.SessionId = so.Service.AddRpcContext(this); if (base.UniqueRequestId == 0) { base.UniqueRequestId = this.SessionId; } var timeoutTask = Schedule(so.Service, SessionId, millisecondsTimeout); if (base.Send(so)) { return(true); } // 发送失败,一般是连接失效,此时删除上下文。 // 其中rpc-trigger-result的原子性由RemoveRpcContext保证。 // Cancel不是必要的。 timeoutTask.Cancel(); // 【注意】当上下文已经其他并发过程删除(得到了处理),那么这里就返回成功。 // see OnSocketDisposed // 这里返回 false 表示真的没有发送成功,外面根据自己需要决定是否重连并再次发送。 Rpc <TArgument, TResult> context = so.Service.RemoveRpcContext <Rpc <TArgument, TResult> >(this.SessionId); return(context == null); }
internal override void Dispatch(Service service, Service.ProtocolFactoryHandle factoryHandle) { if (IsRequest) { service.DispatchProtocol(this, factoryHandle); return; } // response, 从上下文中查找原来发送的rpc对象,并派发该对象。 Rpc <TArgument, TResult> context = service.RemoveRpcContext <Rpc <TArgument, TResult> >(SessionId); if (null == context) { logger.Info("rpc response: lost context, maybe timeout. {0}", this); return; } context.IsRequest = false; context.Result = Result; context.Sender = Sender; context.ResultCode = ResultCode; context.UserState = UserState; if (context.Future != null) { context.Future.SetResult(context.Result); return; // SendForWait,设置结果唤醒等待者。 } context.IsTimeout = false; // not need if (null != context.ResponseHandle) { service.DispatchRpcResponse(context, context.ResponseHandle, factoryHandle); } }