跳到正文

参考

锁定决策

决定 go-sequent 行为的设计决策:SyncInTxn 账本读模型、decimal Money、hash chain、共享 schema Tenancy、Tombstone GDPR、Postgres Outbox、纯库形态与 MIT 许可。

锁定决策

这些选择在实现之前就已确定,代码严格遵循它们,其余文档也以它们为前提。如果你的需求与其中某一条冲突,go-sequent 多半不是合适的工具,否则你得自己维护一个分支。

十项决策

# 决策 含义
Q1 账本读模型使用 SyncInTxn 在写事务里同步更新余额等读模型
Q2 金额使用 decimal types.Money,禁用 float64
Q3 用 hash chain 发现篡改(按聚合串联事件哈希) 按聚合;没有事件签名
Q4 Tenancy(多租户)为共享 schema + tenant_id 没有 schema-per-tenant 或 database-per-tenant
Q5 GDPR 只做 Tombstone 不做 crypto-shredding
Q6 Outbox 为 Postgres 表轮询 框架里没有 LISTEN/NOTIFY 或消息中间件
Q7 纯库 仓库里没有 HTTP 或 gRPC
Q8 快照使用 JSON 独立版本管理
Q9 永不导入 Ruby Sequent 数据库 仅在概念上受其启发
Q10 以 MIT 许可证开源 仓库与文档公开

Q1:账本读模型用 SyncInTxn

Projector(把事件写成查询用读模型,例如余额表)与 Workflow 在写事务内运行,任何失败都会整体回滚。结果是余额永远不会落后于引起它的事件——提交返回后立刻能读到自己刚写的数据。

代价是 Projector 的工作计入写延迟,缓慢或出错的 Projector 会阻塞写入。账本 Projector 要保持小而确定。非账本路径可以通过 Outbox 做异步投递。见 Publisher。

Q2:decimal 金额

金额是带币种的 decimal 数额,以字符串序列化。框架不使用整数最小单位。金额字段禁用 float64,可用 testkit.BanFloat64Money 与 types.AssertNoFloatMoney 检查。舍入策略属于你的领域,历史金额绝不用浮点数重算。见 Money。

Q3:hash chain,没有签名

每个聚合事件流有一条基于规范事件字段的 SHA-256 链。篡改可在加载时或通过 VerifyChain 发现。事件签名不在范围内。数据库访问控制、加密备份与可选的 WORM 存储,是运维层面的补充手段。见 EventStore 与威胁模型。

Q4:共享 schema + tenant_id

只有一套表。每条命令、聚合、Idempotency 记录和读模型都带租户,唯一键 scope 包含租户。partition_key 可以映射到租户,用于同一 schema 内的物理分区。行级安全是可选的,由你自己决定。见 Tenancy(多租户) 与 分区。

Q5:仅 Tombstone 的 GDPR

响应删除请求时,追加一条标记事件(如 gdpr.SubjectTombstoned),由 Projector 清除或不再提供个人数据——之后读模型不再暴露个人数据。事件保持不可变。不提供 crypto-shredding。物理删除事件行属于特殊运维操作,需要事件流修复工具,且除非处理得当否则会破坏 hash chain。可选的 PayloadProtector 支持对 PII 做字段加密,但不涉及删除或真实性。

Q6:Postgres Outbox 轮询

使用 Outbox 时,消息是写事务里写入 Postgres 表的行,通过 Claim、Ack、Nack 轮询消费。投递语义是至少一次,消费者必须保证同一业务键重复提交只生效一次。见 Publisher。

Q7:纯库

go-sequent 不带 HTTP 服务、gRPC stub、UI 或 ORM。CLI 是运维工具,用于迁移、replay 的 schema 阶段与 Outbox 轮询。你把 command.Service 嵌入自己的进程。

Q8:JSON 快照

快照载荷是 JSON,带 SnapshotVersion,不兼容变更时提升版本号。见 Snapshotting。

Q9:永不导入 Ruby Sequent 数据库

概念模型来自 Sequent,schema、序列化与 API 不是。不提供 dump 或线协议兼容,也没有此类计划。Upcaster 只用于你自己的事件历史。见 相对 Sequent Ruby。

Q10:开源,MIT 许可证

项目以 MIT 许可证开源,文档公开。欢迎在 github.com/go-sequent/go-sequent 提交 issue 与贡献。

基线决策(D1 至 D10)

ID 决策
D1 模块路径为 github.com/go-sequent/go-sequent
D2 PostgreSQL 是第一个也是唯一的生产事件库后端
D3 默认发布模式是写事务内的同步 Projector
D4 UnitOfWork 是 context 级,而不是进程全局
D5 命令与事件默认使用 JSON 编码
D6 业务更正用补偿事件,而不是可变历史
D7 金额字段禁用 float64,金额类型为 decimal
D8 显式注册 Handler,不强制使用反射自动注册
D9 先设计,后实现
D10 仅在概念上受 Sequent 启发,永不导入 Ruby Sequent 数据库

背后的原则

  1. 事件是事实来源,读模型是可丢弃的。
  2. 聚合在处理命令时不读取其他聚合的状态。
  3. 命令、事件与同步更新的读模型共享一个数据库事务,异步模式需要显式启用。
  4. 默认开启金融相关特性:decimal 金额、Idempotency 键、每条命令的审计元数据。
  5. 用朴素的 Go:接口、构造函数、context.Context,没有全局可变单例。

相关

文档随 go-sequent 源码更新;若与 API 不一致,以源码为准。