diff --git a/GameFrameX.Core/Actors/Impl/ActorLimit.cs b/GameFrameX.Core/Actors/Impl/ActorLimit.cs index 1db45a3a1..6ef96cfb2 100644 --- a/GameFrameX.Core/Actors/Impl/ActorLimit.cs +++ b/GameFrameX.Core/Actors/Impl/ActorLimit.cs @@ -105,14 +105,14 @@ public static bool AllowCall(long target) /// 目标Actor ID public static void EndCall(long self, long target) { - _rule?.EndCall(self, target); + _rule?.EndInFlightCall(self, target); } private interface IRule { bool CanCall(long target); - void EndCall(long self, long target); + void EndInFlightCall(long self, long target); } @@ -172,7 +172,7 @@ private bool CanCall(long self, long target) /// /// 调用方Actor ID /// 目标Actor ID - void IRule.EndCall(long self, long target) + void IRule.EndInFlightCall(long self, long target) { // IO 上下文与自调用未登记,无需移除 if (self == 0 || self == target) diff --git a/GameFrameX.Core/BaseHandler/RPC/BaseRpcComponentHandler.cs b/GameFrameX.Core/BaseHandler/RPC/BaseRpcComponentHandler.cs index 67303557a..6513db086 100644 --- a/GameFrameX.Core/BaseHandler/RPC/BaseRpcComponentHandler.cs +++ b/GameFrameX.Core/BaseHandler/RPC/BaseRpcComponentHandler.cs @@ -159,22 +159,7 @@ private async Task ExecuteWorkAsync(int timeout, CancellationToken cancellationT { // Localization: Core.MessageHandler.RpcComponentExecutionTimeout - BaseRpcComponentHandler组件RPC执行超时,消息类型:{0} 超时:{1}ms LogHelper.Error(LocalizationService.GetString(Localization.Keys.Core.MessageHandler.RpcComponentExecutionTimeout, RequestMessage.GetType().FullName, timeout)); - - // 超时响应使用独立池化实例:孤儿业务任务仍持有原响应,其写入不得污染已回写的超时响应 - var timeoutResponse = MessageObjectPoolHelper.Get(); - try - { - timeoutResponse.ErrorCode = OperationErrorCode.TimeOut; - timeoutResponse.SetUniqueId(requestId); - if (NetworkChannel != null && !NetworkChannel.IsClosed()) - { - await NetworkChannel.WriteAsync(timeoutResponse); - } - } - finally - { - MessageObjectPoolHelper.Return(timeoutResponse); - } + await WriteTimeoutResponseAsync(requestId); // 原响应经终态延续归还,此处不再写回 return; @@ -212,29 +197,60 @@ private async Task ExecuteWorkAsync(int timeout, CancellationToken cancellationT } finally { - // 任意路径(含通道关闭早退、写通道异常)均归还响应对象,避免对象池耗尽; - // 超时孤儿业务任务未到终态时,经终态延续归还(对齐 BaseRpcMessageHandler 模式) - if (coreTask == null || coreTask.IsCompleted) + ReturnResponseAtTerminalState(coreTask, response); + } + } + + /// + /// 回写独立的超时响应(池化实例,写完即归还):孤儿业务任务仍持有原响应,其写入不得污染已回写的超时响应。 + /// + /// 请求唯一标识,超时响应需携带 / The request id to carry on the timeout response + private async Task WriteTimeoutResponseAsync(int requestId) + { + var timeoutResponse = MessageObjectPoolHelper.Get(); + try + { + timeoutResponse.ErrorCode = OperationErrorCode.TimeOut; + timeoutResponse.SetUniqueId(requestId); + if (NetworkChannel != null && !NetworkChannel.IsClosed()) { - if (response != null) - { - MessageObjectPoolHelper.Return(response); - } + await NetworkChannel.WriteAsync(timeoutResponse); } - else + } + finally + { + MessageObjectPoolHelper.Return(timeoutResponse); + } + } + + /// + /// 在响应到达终态时归还池化实例:核心任务已完成立即归还;孤儿业务任务(取消/超时后仍在运行, + /// 持有 response 引用)经终态延续归还,避免并发改写撕裂与对象池耗尽。 + /// + /// 业务核心任务 / The business core task + /// 本次执行使用的池化响应 / The pooled response used by this execution + private static void ReturnResponseAtTerminalState(Task coreTask, TResponse response) + { + if (coreTask == null || coreTask.IsCompleted) + { + if (response != null) { - _ = coreTask.ContinueWith((completedTask, state) => - { - _ = completedTask.Exception; - var orphanResponse = (TResponse)state; - if (orphanResponse != null) - { - MessageObjectPoolHelper.Return(orphanResponse); - } - }, response, CancellationToken.None, - TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); + MessageObjectPoolHelper.Return(response); } + + return; } + + _ = coreTask.ContinueWith((completedTask, state) => + { + _ = completedTask.Exception; + var orphanResponse = (TResponse)state; + if (orphanResponse != null) + { + MessageObjectPoolHelper.Return(orphanResponse); + } + }, response, CancellationToken.None, + TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); } ///