Mud.Feishu.Redis
2.0.4
See the version list below for details.
dotnet add package Mud.Feishu.Redis --version 2.0.4
NuGet\Install-Package Mud.Feishu.Redis -Version 2.0.4
<PackageReference Include="Mud.Feishu.Redis" Version="2.0.4" />
<PackageVersion Include="Mud.Feishu.Redis" Version="2.0.4" />
<PackageReference Include="Mud.Feishu.Redis" />
paket add Mud.Feishu.Redis --version 2.0.4
#r "nuget: Mud.Feishu.Redis, 2.0.4"
#:package Mud.Feishu.Redis@2.0.4
#addin nuget:?package=Mud.Feishu.Redis&version=2.0.4
#tool nuget:?package=Mud.Feishu.Redis&version=2.0.4
Mud.Feishu.Redis
飞书事件订阅组件 Redis 分布式去重扩展。
功能特性
- 事件去重: 基于 EventId 的分布式去重,防止重复处理同一事件
- Nonce 去重: 防止重放攻击,确保请求的唯一性
- SeqID 去重: WebSocket 二进制消息序列号去重,防止重复处理
- 原子性操作: 使用 Redis SETNX + EXPIRE 确保去重操作的原子性
- 自动过期: Redis 自动清理过期数据,无需手动维护
- 分布式支持: 适用于多实例部署场景
安装
dotnet add package Mud.Feishu.Redis
快速开始
配置 Redis 连接
在 appsettings.json 中添加配置:
{
"Feishu": {
"Redis": {
"ConnectionString": "localhost:6379",
"EventCacheExpiration": "24:00:00",
"NonceTtl": "00:05:00",
"SeqIdCacheExpiration": "24:00:00",
"EventKeyPrefix": "feishu:event:",
"NonceKeyPrefix": "feishu:nonce:",
"SeqIdKeyPrefix": "feishu:seqid:",
"ConnectTimeout": 5000,
"SyncTimeout": 5000,
"Ssl": false,
"AllowAdmin": true
}
}
}
注册服务
注册所有去重服务
using Mud.Feishu.Redis.Extensions;
// 自动从配置文件读取 Redis 连接信息并注册所有去重服务
builder.Services
.AddFeishuRedis()
.AddFeishuRedisDeduplicators();
单独注册服务
// 只注册事件去重服务
builder.Services
.AddFeishuRedis()
.AddFeishuRedisEventDeduplicator();
// 只注册 Nonce 去重服务
builder.Services
.AddFeishuRedis()
.AddFeishuRedisNonceDeduplicator();
// 只注册 SeqID 去重服务
builder.Services
.AddFeishuRedis()
.AddFeishuRedisSeqIDDeduplicator();
完整示例
var builder = WebApplication.CreateBuilder(args);
// 注册 Redis 服务(从配置文件读取)
builder.Services
.AddFeishuRedis()
.AddFeishuRedisDeduplicators()
.AddFeishuWebSocket(options =>
{
options.AppId = builder.Configuration["Feishu:AppId"];
options.AppSecret = builder.Configuration["Feishu:AppSecret"];
});
var app = builder.Build();
app.Run();
配置选项
RedisOptions 配置项
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
ConnectionString |
string | "localhost:6379" | Redis 连接字符串 |
EventCacheExpiration |
TimeSpan | 24小时 | 事件去重缓存过期时间 |
NonceTtl |
TimeSpan | 5分钟 | Nonce 有效期 |
SeqIdCacheExpiration |
TimeSpan | 24小时 | SeqID 去重缓存过期时间 |
EventKeyPrefix |
string | "feishu:event:" | 事件去重键前缀 |
NonceKeyPrefix |
string | "feishu:nonce:" | Nonce 去重键前缀 |
SeqIdKeyPrefix |
string | "feishu:seqid:" | SeqID 去重键前缀 |
ConnectTimeout |
int | 5000ms | 连接超时时间 |
SyncTimeout |
int | 5000ms | 同步超时时间 |
Ssl |
bool | false | 是否启用 TLS/SSL |
AllowAdmin |
bool | true | 是否允许管理员操作 |
Redis 数据结构
事件去重
- Key:
{keyPrefix}{eventId} - Type: String
- Value: "1"
- TTL: 由
cacheExpiration指定
Nonce 去重
- Key:
{keyPrefix}{nonce} - Type: String
- Value: "1"
- TTL: 由
nonceTtl指定
SeqID 去重
- Key:
{keyPrefix}{seqId} - Type: String
- Value: "1"
- TTL: 由
cacheExpiration指定 - Sorted Set:
{keyPrefix}set(用于记录已处理的 SeqID)
常见问题
1. 如何更改默认的缓存过期时间?
在配置文件中修改:
{
"Feishu": {
"Redis": {
"EventCacheExpiration": "7.00:00:00",
"NonceTtl": "00:10:00",
"SeqIdCacheExpiration": "7.00:00:00"
}
}
}
2. 多个环境如何隔离数据?
通过配置文件设置不同的键前缀:
开发环境 appsettings.Development.json:
{
"Feishu": {
"Redis": {
"EventKeyPrefix": "dev:feishu:event:",
"NonceKeyPrefix": "dev:feishu:nonce:",
"SeqIdKeyPrefix": "dev:feishu:seqid:"
}
}
}
生产环境 appsettings.Production.json:
{
"Feishu": {
"Redis": {
"EventKeyPrefix": "prod:feishu:event:",
"NonceKeyPrefix": "prod:feishu:nonce:",
"SeqIdKeyPrefix": "prod:feishu:seqid:"
}
}
}
3. 如何监控 Redis 去重状态?
每个去重服务都提供了日志记录,可以通过日志查看去重状态:
// 获取已处理的事件数量
var deduplicator = serviceProvider.GetRequiredService<IFeishuEventDistributedDeduplicator>();
var count = await deduplicator.GetCachedCountAsync();
4. 如何使用 TLS/SSL 连接 Redis?
在配置文件中启用 SSL:
{
"Feishu": {
"Redis": {
"ConnectionString": "secure.redis.com:6380,password=xxx",
"Ssl": true
}
}
}
或使用 rediss:// 协议:
{
"Feishu": {
"Redis": {
"ConnectionString": "rediss://secure.redis.com:6380"
}
}
}
5. Redis 异常时的降级策略
当 Redis 连接失败或操作异常时,本库提供了多种降级策略:
5.1 标准去重器的异常行为
RedisFeishuEventDistributedDeduplicator、RedisFeishuNonceDistributedDeduplicator 和 RedisFeishuSeqIDDeduplicator 在 Redis 异常时的行为:
- IsDuplicateAsync: 返回
false(允许处理事件,但记录错误日志) - MarkAsProcessedAsync: 返回
false(标记失败,但记录错误日志)
影响: Redis 故障时可能导致重复处理事件,但不会阻塞整个系统。
适用场景: 对重复处理容忍度较高的场景,如日志记录、统计分析等。
5.2 带降级的去重器
RedisFeishuEventDistributedDeduplicatorWithFallback 提供了更智能的降级策略:
- Redis 正常时使用 Redis 去重
- Redis 故障时自动降级到内存去重
- 支持 fallback 配置(内存缓存过期时间、清理间隔等)
使用示例:
builder.Services
.AddFeishuRedis()
.AddFeishuRedisEventDeduplicatorWithFallback(options =>
{
options.MemoryCacheExpiration = TimeSpan.FromHours(1);
options.MemoryCacheCleanupInterval = TimeSpan.FromMinutes(10);
});
适用场景: 对去重要求较高,但可以在 Redis 故障时暂时降级到内存去重的场景。
5.3 选择建议
| 去重器类型 | Redis 故障时行为 | 适用场景 |
|---|---|---|
RedisFeishuEventDistributedDeduplicator |
允许重复处理,不阻塞 | 日志分析、统计等容忍重复的场景 |
RedisFeishuEventDistributedDeduplicatorWithFallback |
降级到内存去重 | 对去重要求高,可接受临时内存存储的场景 |
| 自定义处理 | 抛出异常或自定义逻辑 | 需要精确控制异常行为的场景 |
5.4 最佳实践
- 监控 Redis 健康状态: 实现健康检查,及时发现 Redis 故障
- 配置告警: 当 Redis 连接失败超过阈值时发送告警
- 定期备份: 对于关键业务,定期将内存缓存同步到 Redis
- 使用连接池: 配置合理的连接池大小,提高 Redis 连接稳定性
- 启用 Redis 持久化: 使用 RDB 或 AOF 持久化,防止数据丢失
// 建议配置
builder.Services
.AddFeishuRedis(options =>
{
options.ConnectionString = "localhost:6379";
options.ConnectTimeout = 5000;
options.SyncTimeout = 5000;
options.ConnectRetry = 3;
})
.AddFeishuRedisEventDeduplicatorWithFallback(fallbackOptions =>
{
fallbackOptions.MemoryCacheExpiration = TimeSpan.FromHours(2);
fallbackOptions.MemoryCacheCleanupInterval = TimeSpan.FromMinutes(5);
});
// 添加健康检查
builder.Services.AddHealthChecks()
.AddRedis(options.ConnectionString, name: "redis");
许可证
MIT License
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Microsoft.Extensions.Configuration.Binder (>= 8.0.2)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.2)
- Microsoft.Extensions.Diagnostics.HealthChecks (>= 8.0.1)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.3)
- Microsoft.Extensions.Options (>= 8.0.2)
- Mud.Feishu.Abstractions (>= 2.0.4)
- StackExchange.Redis (>= 2.8.16)
- System.Text.Json (>= 10.0.2)
-
net10.0
- Microsoft.Extensions.Configuration.Binder (>= 10.0.4)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.4)
- Microsoft.Extensions.Diagnostics.HealthChecks (>= 10.0.4)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.4)
- Microsoft.Extensions.Options (>= 10.0.4)
- Mud.Feishu.Abstractions (>= 2.0.4)
- StackExchange.Redis (>= 2.10.1)
-
net6.0
- Microsoft.Extensions.Configuration.Binder (>= 8.0.2)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.2)
- Microsoft.Extensions.Diagnostics.HealthChecks (>= 8.0.1)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.3)
- Microsoft.Extensions.Options (>= 8.0.2)
- Mud.Feishu.Abstractions (>= 2.0.4)
- StackExchange.Redis (>= 2.8.16)
-
net8.0
- Microsoft.Extensions.Configuration.Binder (>= 10.0.4)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.4)
- Microsoft.Extensions.Diagnostics.HealthChecks (>= 10.0.4)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.4)
- Microsoft.Extensions.Options (>= 10.0.4)
- Mud.Feishu.Abstractions (>= 2.0.4)
- StackExchange.Redis (>= 2.10.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated | |
|---|---|---|---|
| 3.0.0-preview3 | 56 | 5/22/2026 | |
| 3.0.0-preview2 | 117 | 5/11/2026 | |
| 3.0.0-preview1 | 148 | 5/1/2026 | |
| 2.1.3 | 90 | 5/22/2026 | |
| 2.1.2 | 126 | 5/12/2026 | |
| 2.1.1 | 104 | 5/11/2026 | |
| 2.1.0 | 121 | 5/1/2026 | |
| 2.0.9 | 178 | 4/24/2026 | |
| 2.0.8 | 153 | 4/12/2026 | |
| 2.0.7 | 158 | 4/7/2026 | |
| 2.0.6 | 111 | 4/5/2026 | |
| 2.0.5 | 202 | 3/28/2026 | |
| 2.0.4 | 138 | 3/19/2026 | |
| 2.0.3 | 118 | 2/26/2026 | |
| 2.0.2 | 122 | 1/30/2026 | |
| 2.0.1 | 118 | 1/27/2026 | |
| 1.2.2 | 143 | 1/19/2026 | |
| 1.2.1 | 145 | 1/16/2026 | |
| 1.2.0 | 165 | 1/14/2026 | |
| 1.1.2 | 137 | 1/11/2026 |