From 2d2157749cb1c1cda34e4c74abaf835db8e9f502 Mon Sep 17 00:00:00 2001 From: Blank Date: Sun, 1 Nov 2026 20:43:30 +0800 Subject: [PATCH] =?UTF-8?q?fix(discovery):=20=E7=BB=88=E6=80=81=E5=BF=83?= =?UTF-8?q?=E8=B7=B3=E5=86=99=E5=85=A5=E5=8A=A0=202s=20=E8=B6=85=E6=97=B6?= =?UTF-8?q?=E5=B9=B6=E8=84=B1=E7=A6=BB=E5=90=8C=E6=AD=A5=E4=B8=8A=E4=B8=8B?= =?UTF-8?q?=E6=96=87=EF=BC=88=E4=BF=AE=E5=A4=8D=20#698=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Discovery/DiscoveryRegistry.cs | 37 +++++++++++++------ GameFrameX.Localization/Keys.Discovery.cs | 9 +++++ .../Localization/Messages/Resources.resx | 4 ++ .../Messages/Resources.zh-CN.resx | 4 ++ 4 files changed, 43 insertions(+), 11 deletions(-) diff --git a/GameFrameX.Discovery/Discovery/DiscoveryRegistry.cs b/GameFrameX.Discovery/Discovery/DiscoveryRegistry.cs index 35634336a..ce3b54361 100644 --- a/GameFrameX.Discovery/Discovery/DiscoveryRegistry.cs +++ b/GameFrameX.Discovery/Discovery/DiscoveryRegistry.cs @@ -355,11 +355,7 @@ public void Dispose() try { _loopCancellation.Cancel(); - WriteStoppedAsync().GetAwaiter().GetResult(); - } - catch (Exception) - { - // 尽力而为:进程退出路径上数据库不可达时无法补写终态,交给 TTL 兜底清除。 + WriteTerminalHeartbeatSafely(); } finally { @@ -470,13 +466,32 @@ private static async Task WaitLoopAsync(Task loopTask) /// 事件参数 / The event arguments private void OnProcessExit(object sender, EventArgs eventArguments) { - try - { - WriteStoppedAsync().GetAwaiter().GetResult(); - } - catch (Exception) + WriteTerminalHeartbeatSafely(); + } + + /// + /// 终态心跳的同步尽力写入:2 秒超时 + Task.Run 脱离可能的 SynchronizationContext, + /// 避免存在同步上下文时死锁;失败/超时记日志不阻塞退出(TTL 兜底清除)。 + /// + /// + /// Best-effort synchronous write of the terminal heartbeat: a 2-second timeout and + /// Task.Run to escape any SynchronizationContext (deadlock guard); failures and + /// timeouts are logged without blocking exit (TTL cleanup is the fallback). + /// + private void WriteTerminalHeartbeatSafely() + { + using (var cancellation = new CancellationTokenSource(TimeSpan.FromSeconds(2))) { - // 进程退出路径上数据库不可达时无法补写终态,交给 TTL 兜底清除。 + try + { + Task.Run(() => WriteStoppedAsync(), cancellation.Token).GetAwaiter().GetResult(); + } + catch (Exception exception) + { + // 尽力而为:进程退出路径上数据库不可达/超时时无法补写终态,交给 TTL 兜底清除。 + // Localization: Discovery.Registry.TerminalHeartbeatFailed - [DiscoveryRegistry] 终态心跳写入失败(超时 2s 内未完成),交给 TTL 兜底清除 + LogHelper.Error(exception, LocalizationService.GetString(Localization.Keys.Discovery.Registry.TerminalHeartbeatFailed)); + } } } diff --git a/GameFrameX.Localization/Keys.Discovery.cs b/GameFrameX.Localization/Keys.Discovery.cs index 436a4ef24..ff29e9574 100644 --- a/GameFrameX.Localization/Keys.Discovery.cs +++ b/GameFrameX.Localization/Keys.Discovery.cs @@ -235,6 +235,15 @@ public static class Registry /// public const string TtlCleanupFailed = "Discovery.Registry.TtlCleanupFailed"; + /// + /// [DiscoveryRegistry] 终态心跳写入失败(超时 2s 内未完成),交给 TTL 兜底清除 + /// + /// + /// 键名: Discovery.Registry.TerminalHeartbeatFailed + /// 用途: Dispose/ProcessExit 终态心跳尽力写入失败或超时时的错误日志 + /// + public const string TerminalHeartbeatFailed = "Discovery.Registry.TerminalHeartbeatFailed"; + /// /// 附加广播端点未被发布:服务进程类型 '{0}' 不是本进程心跳承载的首选类型 '{1}'(心跳文档单 Role 模型,非首选类型不跨进程可达) /// diff --git a/GameFrameX.Localization/Localization/Messages/Resources.resx b/GameFrameX.Localization/Localization/Messages/Resources.resx index f7a878775..65350f2b5 100644 --- a/GameFrameX.Localization/Localization/Messages/Resources.resx +++ b/GameFrameX.Localization/Localization/Messages/Resources.resx @@ -1984,6 +1984,10 @@ [AdvertiseEndpointEnvironment] egress address detection failed; falling back to the machine name {0} as the advertise host. Set {1} explicitly when cross-process routing is required. + + + [DiscoveryRegistry] terminal heartbeat write failed (not completed within the 2s timeout); leaving it to TTL cleanup + [DiscoveryRegistry] heartbeat upsert failed for instance {0}; will retry next interval diff --git a/GameFrameX.Localization/Localization/Messages/Resources.zh-CN.resx b/GameFrameX.Localization/Localization/Messages/Resources.zh-CN.resx index d06b145de..24e45d32b 100644 --- a/GameFrameX.Localization/Localization/Messages/Resources.zh-CN.resx +++ b/GameFrameX.Localization/Localization/Messages/Resources.zh-CN.resx @@ -1978,6 +1978,10 @@ [AdvertiseEndpointEnvironment] 出口地址探测失败;回退使用机器名 {0} 作为广播主机。需要跨进程路由时请显式设置 {1} + + + [DiscoveryRegistry] 终态心跳写入失败(超时 2s 内未完成),交给 TTL 兜底清除 + [DiscoveryRegistry] 实例 {0} 心跳写入失败;将在下个间隔重试