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);
}
///