CAP注册须在AddDbContext之后、Build()之前,且需配对UseEntityFramework<TContext>()与UseSqlServer();本地消息表需手动迁移或建表,否则发布静默失败。

CAP 不是“用了就一致”的黑盒,它只保证消息不丢、能重试、有持久化;真正的最终一致性,得靠你设计幂等消费逻辑、控制消息顺序、选对存储与传输组合。跳过这些环节直接上线,90% 的生产问题都出在这儿。
怎么在 Program.cs 里正确注册 CAP(.NET 6+)
CAP 的注册必须在 AddDbContext 之后、Build() 之前完成,且数据库上下文必须已注册到 DI 容器中——否则 UseEntityFramework<TContext>() 会静默失败,本地消息表(Published/Received)压根不会创建。
- 先注册 DbContext(含连接字符串和迁移配置),再调用
services.AddCap(...) -
UseEntityFramework<TContext>()和UseSqlServer(...)必须配对:前者声明 ORM 绑定,后者声明实际数据库提供者;不能只写一个 - RabbitMQ 配置里
cfg.Port默认是 5672,但如果你用 Docker 启动的官方镜像,宿主机映射端口可能不是这个,务必核对docker ps输出中的 PORTS 列 - 开发环境可临时用
UseInMemoryStorage()+UseInMemoryMessageQueue()快速验证流程,但切勿用于集成测试——内存队列不模拟重试、堆积、ACK 失败等真实行为
为什么消费者反复收到同一条消息(重复消费)
这不是 CAP 的 bug,而是“至少一次投递”模型下的必然现象。CAP 在消费者方法返回后才向 RabbitMQ 发送 ACK;若方法执行成功但网络抖动导致 ACK 未送达,Broker 就会重发。此时若你的处理逻辑没做幂等,数据就会错乱。
- 最简方案:在消费方法开头查数据库,用
MessageId或业务唯一键(如OrderId)判断是否已处理,已存在则直接 return - 避免用
try-catch包裹全部逻辑再吞异常——CAP 依赖未捕获异常触发重试,吞掉就等于放弃可靠性保障 - 慎用 Redis 分布式锁控制幂等:高并发下锁竞争会拖慢吞吐,且锁过期时间难精确匹配业务耗时;优先用数据库唯一约束 + upsert 语句
-
CapSubscribeAttribute的Group参数影响重试队列隔离,不同 Group 的订阅者互不影响,但同一 Group 内多个实例会竞争同一批消息
如何确保“创建订单→扣减库存→发货通知”严格顺序执行
CAP 本身不保证全局消息顺序,只在单个 Topic/Exchange + 单个 Partition 内维持 FIFO。跨服务或跨业务实体的消息天然无序,强行要求全局顺序会严重牺牲扩展性。
- 业务上拆解:把强顺序依赖收拢到同一个微服务内处理(例如订单服务内部完成状态机流转),只对外发布终态事件(如
OrderCreated、OrderShipped) - 技术上分区:用 Kafka 时,按
OrderId做 key 分区,确保同一订单的所有事件落到同一 partition;RabbitMQ 则需配合RoutingKey+ 单队列单消费者模式(牺牲并行度) - 绝对不要依赖 CAP 的
RetryCount或Delay配置来“模拟”顺序——重试是容错机制,不是调度工具 - 如果必须跨服务保序,加版本号字段(如
Version),消费者收到消息时比对当前业务实体最新版本,旧版本直接丢弃
本地消息表没生成、Published 表始终为空
这是新手最常卡住的点:CAP 的消息表不是自动建库建表的,它依赖 EF Core Migration 或显式初始化。即使你写了 UseSqlServer,若数据库里没有 Published 表,CAP 启动时也不会报错,只是所有发布操作静默失败。
- 检查数据库连接字符串是否指向目标库,且该库已存在(CAP 不会自动创建数据库)
- 运行
dotnet ef migrations add InitCapTables+dotnet ef database update,确保 EF 迁移包含 CAP 所需的两张表结构 - 若用 Dapper,必须手动执行 SQL 脚本建表(脚本在 CAP GitHub 的
src/DotNetCore.CAP.SqlServer/scripts目录下) - 启动日志里搜
"CAP: Starting"和"CAP: Local message table initialized",没看到后者说明初始化失败,接着查 EF 日志或数据库权限
真正难的从来不是“怎么让 CAP 跑起来”,而是想清楚哪些消息必须幂等、哪些顺序不可破、哪些失败可以重试、哪些该直接告警。CAP 把分布式事务的骨架搭好了,血肉得你自己一针一线缝上去。


















