Documentation
¶
Overview ¶
Package txn 提供跨域事务协调:让 wallet/storage/notification 等域包 在一个逻辑事务边界内原子提交或全部回滚。
背景:beauty 各域包(wallet/storage/account)各自管理状态,但应用常需 "原子地:扣钱包 + 写存档 + 发通知"——任一步失败,前面已改的要回滚。 beauty 是 DB-agnostic,因此做成通用的两阶段提交协调器(Two-Phase Commit):
- Prepare:各 Participant 校验能否提交,并把变更暂存到 staging(不落库);
- 全部 Prepare 成功 → 依次 Commit(落库);
- 任一 Prepare 失败 → 已 Prepare 的依次 Rollback(丢弃 staging)。
用法(业务层负责接线,各域包无需感知 txn):
walletStage := wallet.NewStaging() // 域包提供 staging 视图(见下)
storageStage := storage.NewStaging()
coord := txn.New()
coord.Enlist("wallet", walletStage, walletStage.Commit, walletStage.Rollback)
coord.Enlist("storage", storageStage, storageStage.Commit, storageStage.Rollback)
err := coord.Run(func() error {
// 在 staging 视图上操作,不直接改主库
if _, _, err := walletStage.Apply(...); err != nil { return err }
if err := storageStage.Set(...); err != nil { return err }
return nil
})
// Run 返回 nil → 已 Commit;返回 err → 已 Rollback。
域包如何提供 staging:实现 Participant 接口即可。最简形式是"先在副本上操作, Commit 时把副本 swap 到主库,Rollback 时丢弃副本"。本包不规定 staging 实现, 只协调 Prepare/Commit/Rollback 的调用顺序与原子性。
并发安全:一个 Coordinator 一次只 Run 一个事务(内部加锁);多次 Run 串行。 Prepare/Commit/Rollback 的错误会被收集,任一 Commit 失败后续 Commit 仍执行 (best-effort),但会返回聚合错误——调用方据此做补偿。
Post-commit 钩子(OnCommit):注册在全部 Participant Commit 成功后才执行的回调, 用于"提交后副作用"——发通知 / 触发 webhook / 写审计。任一 Commit 失败或事务 回滚,钩子不执行,避免"事务回滚了但通知已发出"的竞态。钩子在独立 goroutine 异步执行,不阻塞 Run 返回,panic 被恢复(复用 pkg/safe)。
Index ¶
- type Coordinator
- func (c *Coordinator) Enlist(name string, p Participant)
- func (c *Coordinator) EnlistFunc(name string, prepare, commit, rollback func(ctx context.Context) error)
- func (c *Coordinator) OnCommit(fn func(ctx context.Context) error)
- func (c *Coordinator) Run(ctx context.Context, body func() error) error
- type Participant
- type ParticipantFunc
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Coordinator ¶
type Coordinator struct {
// contains filtered or unexported fields
}
Coordinator 协调多个 Participant 的两阶段提交。 零值不可用,用 New 构造。
func (*Coordinator) Enlist ¶
func (c *Coordinator) Enlist(name string, p Participant)
Enlist 注册一个 Participant,按注册顺序参与 Prepare/Commit(逆序 Rollback)。 name 仅用于错误信息。可在 Run 前多次 Enlist。
func (*Coordinator) EnlistFunc ¶
func (c *Coordinator) EnlistFunc(name string, prepare, commit, rollback func(ctx context.Context) error)
EnlistFunc 函数形式注册(等价于 Enlist(name, ParticipantFunc{...}))。
func (*Coordinator) OnCommit ¶
func (c *Coordinator) OnCommit(fn func(ctx context.Context) error)
OnCommit 注册一个 post-commit 钩子:在所有 Participant Commit 全部成功后, 按注册顺序异步执行。任一 Commit 失败或事务回滚时,钩子不执行。
解决"提交后副作用"的竞态:在 body 里直接发通知/webhook,若事务回滚, 通知已发出却无对应数据。OnCommit 把这类副作用推迟到提交成功后。
钩子在独立 goroutine 执行(context.WithoutCancel 派生自 Run 的 ctx), 不阻塞 Run 返回,panic 被恢复(复用 pkg/safe)。可在 Run 前或 body 内注册。
func (*Coordinator) Run ¶
func (c *Coordinator) Run(ctx context.Context, body func() error) error
Run 执行一个事务:body 在各 Participant 已 Prepare 后调用,body 内对 staging 视图操作;body 返回 nil 则 Commit 全部,返回 err 则 Rollback 全部。
调用顺序:
- 依次 Prepare(顺序);任一失败 → 已 Prepare 的逆序 Rollback,返回该错误;
- body();body 返回 err → 已 Prepare 的逆序 Rollback,返回 body 的 err;
- body 成功 → 依次 Commit(顺序);任一 Commit 失败 → 仍继续后续 Commit (best-effort,避免部分提交导致不一致),最终返回聚合错误。
返回 nil 表示事务提交成功;返回 error 表示已 Rollback 或部分提交失败。
type Participant ¶
type Participant interface {
Prepare(ctx context.Context) error
Commit(ctx context.Context) error
Rollback(ctx context.Context) error
}
Participant 一个参与协调的域。三阶段:
- Prepare:校验 + 暂存变更。返回 error 表示无法提交(此时协调器会回滚)。
- Commit:把暂存变更落库。返回 error 表示提交失败(已尽力,调用方做补偿)。
- Rollback:丢弃暂存变更,恢复到 Prepare 前状态。
实现须幂等:Commit/Rollback 被重复调用不应有副作用。