VdaStrictBindingStartupGuardService.cs
3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Rcs.Domain.Settings;
using StackExchange.Redis;
namespace Rcs.Infrastructure.Services;
/// <summary>
/// VDA5050 严格 binding 切换启动守卫。
/// 若检测到停机切换前遗留的旧路径缓存/锁数据,则自动清除后再启动。
/// </summary>
public sealed class VdaStrictBindingStartupGuardService : IHostedService
{
private readonly ILogger<VdaStrictBindingStartupGuardService> _logger;
private readonly IConnectionMultiplexer _redis;
private readonly AppSettings _settings;
public VdaStrictBindingStartupGuardService(
ILogger<VdaStrictBindingStartupGuardService> logger,
IConnectionMultiplexer redis,
IOptions<AppSettings> settings)
{
_logger = logger;
_redis = redis;
_settings = settings.Value;
}
public Task StartAsync(CancellationToken cancellationToken)
{
var endPoints = _redis.GetEndPoints();
if (endPoints.Length == 0)
{
_logger.LogWarning("[VDA严格守卫] 未发现 Redis 端点,跳过严格 binding 启动检查。");
return Task.CompletedTask;
}
var patterns = new[]
{
$"{_settings.Redis.KeyPrefixes.VdaPath}:*",
$"{_settings.Redis.KeyPrefixes.NodeLockPrefix}:*",
$"{_settings.Redis.KeyPrefixes.EdgeLockPrefix}:*",
$"{_settings.Redis.KeyPrefixes.RobotLockResourcesPrefix}:*"
};
foreach (var endPoint in endPoints)
{
cancellationToken.ThrowIfCancellationRequested();
var server = _redis.GetServer(endPoint);
if (!server.IsConnected || server.IsReplica)
{
continue;
}
foreach (var pattern in patterns)
{
var leakedKeys = server.Keys(pattern: pattern, pageSize: 50)
.Select(key => key.ToString())
.ToList();
if (leakedKeys.Count == 0)
{
continue;
}
var sampleKeys = leakedKeys.Take(5);
_logger.LogWarning(
"[VDA严格守卫] 检测到停机切换前遗留的 Redis 键,即将自动清除。Pattern={Pattern}, Count={Count}, SampleKeys={SampleKeys}",
pattern,
leakedKeys.Count,
string.Join(",", sampleKeys));
var db = _redis.GetDatabase();
foreach (var key in leakedKeys)
{
db.KeyDelete(key);
}
_logger.LogInformation(
"[VDA严格守卫] 已清除遗留 Redis 键。Pattern={Pattern}, Count={Count}",
pattern,
leakedKeys.Count);
}
}
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}