FieldWorkClient/Services/RedisService.cs

113 lines
3.8 KiB
C#
Raw Normal View History

using Hopetry.Provider;
using Newtonsoft.Json;
using StackExchange.Redis;
namespace Hopetry.Services
{
public class RedisService : IDisposable
{
private readonly ConnectionMultiplexer _redis;
private readonly IDatabase _db;
private const string Prefix = "client:";
public RedisService(string connectionString)
{
var config = ConfigurationOptions.Parse(connectionString);
config.AbortOnConnectFail = false;
config.ConnectTimeout = 5000;
_redis = ConnectionMultiplexer.Connect(config);
_db = _redis.GetDatabase();
}
// 存储客户端信息自动过期30天
public async Task StoreClientInfoAsync(SystemInfo info)
{
var key = $"{Prefix}{info.MachineId}";
var json = JsonConvert.SerializeObject(info);
2025-04-29 16:30:56 +08:00
await _db.StringSetAsync(key, json, TimeSpan.FromMinutes(5));
}
// 获取单个客户端信息
public async Task<SystemInfo> GetClientInfoAsync(string machineId)
{
var json = await _db.StringGetAsync($"{Prefix}{machineId}");
return json.HasValue ? JsonConvert.DeserializeObject<SystemInfo>(json) : null;
}
// 获取所有客户端信息
public async Task<List<SystemInfo>> GetAllClientsAsync()
{
var endpoints = _redis.GetEndPoints();
var server = _redis.GetServer(endpoints.First());
var keys = server.Keys(pattern: $"{Prefix}*").ToArray();
var results = new List<SystemInfo>();
foreach (var key in keys)
{
var json = await _db.StringGetAsync(key);
if (json.HasValue)
{
results.Add(JsonConvert.DeserializeObject<SystemInfo>(json));
}
}
return results;
}
// 删除客户端信息
public async Task<bool> DeleteClientAsync(string machineId)
{
return await _db.KeyDeleteAsync($"{Prefix}{machineId}");
}
2025-04-29 16:30:56 +08:00
// 新增心跳键前缀
private const string HeartbeatPrefix = "heartbeat:";
// 更新客户端心跳(核心新增方法)
public async Task UpdateClientHeartbeatAsync(string machineId)
{
// 同时更新两个键的过期时间:
// 1. 客户端信息键(保持长期有效)
// 2. 心跳状态键(短期存活检测)
var tasks = new List<Task>
{
// 刷新客户端信息过期时间30天
_db.KeyExpireAsync($"{Prefix}{machineId}", TimeSpan.FromMinutes(5)),
// 设置/更新心跳状态带5分钟过期
_db.StringSetAsync(
$"{HeartbeatPrefix}{machineId}",
DateTime.UtcNow.ToString("o"),
expiry: TimeSpan.FromMinutes(5)
)
};
await Task.WhenAll(tasks);
}
// 获取所有活跃客户端ID基于心跳键
public async Task<List<string>> GetActiveClientIdsAsync()
{
var endpoints = _redis.GetEndPoints();
var server = _redis.GetServer(endpoints.First());
// 注意生产环境应改用SCAN
var heartbeatKeys = server.Keys(pattern: $"{HeartbeatPrefix}*");
return heartbeatKeys
.Select(k => k.ToString().Substring(HeartbeatPrefix.Length))
.ToList();
}
// 检查客户端是否活跃
public async Task<bool> IsClientActiveAsync(string machineId)
{
return await _db.KeyExistsAsync($"{HeartbeatPrefix}{machineId}");
}
public void Dispose()
{
_redis?.Dispose();
}
}
}