|
|
@@ -36,7 +36,7 @@ public sealed class EtlInstanceRegistrar : BackgroundService
|
|
|
/// <summary>启动延时:等宿主配置与建表脚本就绪,避免首拍必然失败刷一条 warn。</summary>
|
|
|
private static readonly TimeSpan StartupDelay = TimeSpan.FromSeconds(5);
|
|
|
|
|
|
- /// <summary>下线实例行的保留期。超期且不在被指派槽位上的行会被清理,防止表随重启无限增长。</summary>
|
|
|
+ /// <summary>下线实例行的保留期。超期即清理,防止表随重启无限增长。</summary>
|
|
|
private static readonly TimeSpan DeadInstanceRetention = TimeSpan.FromDays(7);
|
|
|
|
|
|
/// <summary>存活判据:连续三拍没心跳即视为下线,与 <see cref="AidopRunnerState.FreshnessWindow"/> 同宽。</summary>
|
|
|
@@ -232,12 +232,14 @@ public sealed class EtlInstanceRegistrar : BackgroundService
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
- /// 清理早已下线的实例行。**被指派槽位上的行即使心跳超期也保留**——
|
|
|
- /// 运维需要看到「指派槽位上那台机器挂了」,而不是记录凭空消失。
|
|
|
+ /// 清理早已下线的实例行,不分槽位一视同仁。
|
|
|
///
|
|
|
- /// <para>注意这里保留的只是**观测线索**:指派本身存在
|
|
|
- /// <c>ado_etl_runner_designation</c>,即使这些行被清掉也不会丢指派。
|
|
|
- /// 旧模型正相反——指派就寄生在实例行上,所以那时必须靠这个过滤条件兜着。</para>
|
|
|
+ /// <para>旧模型必须特意保住被指派实例的行,因为指派就寄生在
|
|
|
+ /// <c>ado_etl_instance.is_runner</c> 上,删行等于删指派。现在指派独立存在
|
|
|
+ /// <c>ado_etl_runner_designation</c>,这条例外不但没用,还有害:执行机槽位
|
|
|
+ /// 每重启一次留一行,恰恰是重启最勤的那个槽位无限堆积,页面上还会摆着一排
|
|
|
+ /// 早已死掉的同槽位实例。运维要看的「指派槽位上没有活实例」由监控页的
|
|
|
+ /// noLiveRunner 告警给出,不需要靠留尸体来表达。</para>
|
|
|
/// </summary>
|
|
|
private async Task CleanupDeadAsync(CancellationToken ct)
|
|
|
{
|
|
|
@@ -245,14 +247,9 @@ public sealed class EtlInstanceRegistrar : BackgroundService
|
|
|
{
|
|
|
using var scope = _scopeFactory.CreateScope();
|
|
|
var db = scope.ServiceProvider.GetRequiredService<ISqlSugarClient>();
|
|
|
- var instances = scope.ServiceProvider.GetRequiredService<IEtlInstanceStore>();
|
|
|
- var designated = await instances.GetDesignatedSlotAsync(ct);
|
|
|
var cutoff = DateTime.Now - DeadInstanceRetention;
|
|
|
var removed = await db.Deleteable<AdoEtlInstance>()
|
|
|
.Where(x => x.LastHeartbeatAt < cutoff)
|
|
|
- // 必须显式放行 slot_code IS NULL:SQL 里 NULL <> 'x' 求值为 NULL 而非真,
|
|
|
- // 少了这一支,未声明槽位的开发机死行会永远清不掉。
|
|
|
- .WhereIF(designated != null, x => x.SlotCode == null || x.SlotCode != designated)
|
|
|
.ExecuteCommandAsync(ct);
|
|
|
if (removed > 0)
|
|
|
_logger.LogInformation("[EtlInstanceRegistrar] 已清理下线实例 {Count} 行", removed);
|