跳到正文

参考

Event

Event 接口、event.Base 信封、JSON 解码用的类型 Registry、命名约定,以及 upcaster 的位置。

Event

包:event

Event 是已经发生的事实:有类型名和信封。事件写入 EventStore,交给 Projector 与 Workflow,再通过 registry 解码。

接口

type Event interface {
    EventType() string
    AggregateID() uuid.UUID
    SequenceNumber() int64
    CreatedAt() time.Time
}

信封包括 aggregate id、序号和创建时间。聚合调用 Apply 时会填好这些字段。store 把它们放在独立列里,JSON 载荷不必再重复一份。

event.Base

领域事件嵌入 event.Base,在构造函数里设好类型名:

type MoneyDeposited struct {
    event.Base
    Amount types.Money `json:"amount"`
}

func NewMoneyDeposited(amount types.Money) *MoneyDeposited {
    e := &MoneyDeposited{Amount: amount}
    e.SetEventType("bank.MoneyDeposited")
    return e
}

func (e *MoneyDeposited) EventType() string { return "bank.MoneyDeposited" }

Base 实现了 Envelope,另外提供 SetAggregateID、SetSequenceNumber、SetCreatedAt。这些 setter 由聚合和 store 调用,业务代码不要自己调。

Registry

Registry 把已存储的类型名映射到工厂函数,store 靠它把 JSON 解成具体结构体。

r.Register("bank.AccountOpened", func() event.Event { return &AccountOpened{} })

加载任何事件流之前,必须注册所有事件类型。Registry 还提供 New(name) 和 Has(name)。store 与应用要共用同一个 *event.Registry;在门面里就是 app.Events:

app := sequent.New(sequent.Config{})
bank.RegisterEvents(app.Events)
store := memory.New(app.Events) // 同一个 registry

store 若用了另一个 registry,加载时会报未知类型。

命名与形状

  • 用过去时:MoneyDeposited,不要写成 DepositMoney。
  • 类型名带命名空间:bank.MoneyDeposited。这个名字会跟着数据一起存。
  • 事件要小而扁,一个事件一件事。
  • 金额用 types.Money,绝不用 float64。
  • 记的是事实,不是状态快照。聚合靠按序应用事件推出当前状态。

改类型名或改载荷结构需要 upcaster——旧行还挂着旧名字。语义变了,通常应新增事件类型,旧事件原样保留。

Upcaster

Upcaster 在 event/upcast,加载事件时把旧载荷转成新形状:

type Upcaster interface {
    FromType() string
    Upcast(payload json.RawMessage) (toType string, out json.RawMessage, err error)
}

在应用上注册:

app.RegisterUpcaster(upcast.FuncUpcaster{
    From: "bank.MoneyDeposited.v0",
    Fn: func(p json.RawMessage) (string, json.RawMessage, error) {
        // amt 改名为 amount,并返回新类型名
    },
})

Upcaster 是纯函数:JSON 进,JSON 出。链默认最多跟随八次改名。用 SetUpcasters(app.Upcasters) 把链挂到 store 上。规则、兼容矩阵与测试要求见 事件演进。

Upcaster 只处理你自己的历史数据,不是用来读 Ruby Sequent 库的;那条路永远不支持。

修正错误

事件是不可变事实。要纠错,就追加补偿事件(例如冲正),不要改或删事件行。store 加载时会校验 hash chain(按聚合串联事件哈希,用来发现篡改),静默改库会把链弄断。

相关

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