入门
核心闭环
go-sequent 写路径逐步说明:CommandService.Execute、中间件、AuthZ、Handler、Repository.Commit、SyncInTxn 发布、事务提交与 AfterCommit。
核心闭环
go-sequent 里每一次状态变更都走同一个入口:CommandService.Execute(ctx, cmds...)。弄清它内部做了什么,就弄清了这个库的大半。
客户端 / 服务入口
│
▼
CommandService.Execute(ctx, cmds...)
│ 通过 WithinTx 开启事务,ctx 上挂 UnitOfWork
│
│ 对每条命令:
├─ EnsureMeta
├─ Middleware 链(Tenancy、Idempotency……) 外层先执行
├─ Filters(AuthZ)
├─ Command.Validate
├─ Router.Dispatch → CommandHandler
│ Repo.Add / Repo.Load → 聚合方法 → Apply(event)
├─ Repository.Commit
│ EventStore.Append (OCC、唯一键、hash chain)
│ Publisher.Publish → Projectors → Workflows
▼
事务提交 → AfterCommit 钩子
你写什么,库做什么
你编写 Command、Handler、Aggregate、Event 与 Projector(把事件写成查询用读模型,例如余额表)。其余由库提供:command.Service、aggregate.Repository、事件存储与 publish.SyncInTxn。
| 步骤 | 负责方 | 发生了什么 |
|---|---|---|
| 事务与 UnitOfWork | 库 | Execute 经存储的 TxManager 开事务,并把 UnitOfWork 放进 context。 |
| Middleware | 你选择 | 常见是 Tenancy 与 Idempotency,外层优先执行。 |
| Filters | 你选择 | AuthZ 在这里跑;被拒绝就终止该命令。 |
Validate |
你 | 检查命令自身形状。 |
| Handler | 你 | 加载或创建聚合,调用其方法。 |
| Aggregate | 你 | 执行规则,然后 Apply 事件。 |
Commit |
库 | 追加被改过的聚合事件;强制 OCC(用 ExpectedVersion 防并发写冲突)、唯一键与 hash chain。 |
| 发布 | 库 | 同一事务内先跑 Projector,再跑 Workflow(SyncInTxn:在写事务里同步更新读模型)。 |
| AfterCommit | 你 | 经 workflow.RegisterAfterCommit 注册的钩子在事务提交后跑。 |
为什么是一个事务
事件、唯一键、Idempotency 记录与账本读模型要么一起提交,要么都不提交。某个 Projector 返回错误,事件就不会落库。这是 SyncInTxn 的保证,也是 Execute 返回后立刻读到的余额不会过期的原因——提交返回后立刻能读到自己刚写的数据。
不能跟着事务回滚的副作用(例如发邮件)应放进 AfterCommit,而不是 Projector。
一次调用中的多条命令
Execute 接受一个列表。所有命令共享事务和 UnitOfWork,因此要么全部提交,要么全部不提交。两条命令必须原子执行时用它。涉及两个聚合的一次业务操作,通常用一条同时加载两者的命令更清晰,见 领域建模里的转账。
Context 级 UnitOfWork
UnitOfWork 放在 context.Context 里,每次 Execute 一个。不要跨 goroutine 共享。彼此独立的命令走各自独立的 Execute。
各步骤的文档位置
Execute及其选项见 CommandService。- 闭环中段见 Command Handler 与 Repository。
- OCC、唯一键与 hash chain 见 EventStore。
- 闭环末段见 Publisher、Projector 与 Workflow。
- 各项保证合在一起见 写路径一致性。
文档随 go-sequent 源码更新;若与 API 不一致,以源码为准。