suspend

package
v0.0.0-...-1c978d5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 17, 2026 License: Apache-2.0 Imports: 17 Imported by: 0

Documentation

Overview

Package suspend 实现挂起/恢复的持久化:ask_user 与审批等待不再靠 进程内 goroutine 阻塞——飞书审批常常跨小时甚至隔天,占着 goroutine 等、进程一重启全丢,撑不住真实使用。

机制是"卸载重放"(durable execution lite):

  • 挂起:交互点(Ask/Approve)查不到已记录的答案时,持久化待答 记录并返回 ErrSuspended,整轮调用栈退干净,进程不持有任何状态;
  • 恢复:用户的答案(可能在进程重启之后)写入交互日志,原输入 重跑该轮——交互点按确定性键命中日志直接返回答案,越过挂起点;
  • 幂等:mutating 工具的执行结果随轮记入效果日志,重放时命中即 返回记录结果、不二次执行(只读工具与模型调用照常重跑,安全)。

重放路径若与首次运行分叉(模型换了措辞/换了路径),交互键不再命中, 退化为重新提问——多问一次,但不会答非所问,失败模式是安全的。

Index

Constants

View Source
const DefaultApprovalPrompt = "Approval required for an operation:\n%s\nArguments: %s\nReply \"yes\" to proceed, anything else to cancel."

DefaultApprovalPrompt formats the approval question sent to the user; the two %s are the operation description and its arguments. Shared by the suspend-mode and in-process HITL paths so the wording stays identical.

Variables

This section is empty.

Functions

func AnswerPending

func AnswerPending(ctx context.Context, kv store.KV, interactionID, answer string) error

AnswerPending 写入用户答案(恢复入口,进程重启后同样可用)。

func DurableEffects

func DurableEffects(caps []capability.Capability) []capability.Capability

DurableEffects 给能力集套上效果日志闸门(Ring 0):mutating 能力的 执行结果随轮记录,重放(挂起恢复后的重跑)命中即返回记录结果、 不二次执行——审批过的转账不会因为恢复而转两次。只读能力照常重跑。 ctx 无日志(非挂起模式)时零开销。

套闸顺序:审批之内、截断之外——重放时先由交互日志越过审批,再由 本闸跳过执行;记录的是模型实际看到的(截断后)结果。

func Interactor

func Interactor(j *Journal, notify Notify) runctx.Interactor

Interactor 返回可挂起的交互通道:Ask/Approve 不阻塞——命中日志即 返回答案(重放),未命中则送出问题、记录待答并以 ErrSuspended 退栈。

func IsAffirmative

func IsAffirmative(reply string) bool

IsAffirmative reports whether a user's reply approves the pending operation. It accepts common affirmatives in English and Chinese so a multilingual deployment works without extra configuration.

func NewTurnID

func NewTurnID() string

NewTurnID 生成一轮的唯一标识(时间 + 随机),恢复的轮次沿用首跑的 ID。

func SavePendingTurn

func SavePendingTurn(ctx context.Context, kv store.KV, sessionKey string, rec PendingTurn) error

SavePendingTurn 持久化挂起中的轮次(同会话同时只有一条)。

func WithJournal

func WithJournal(ctx context.Context, j *Journal) context.Context

WithJournal 把挂起日志装入 ctx,对下游交互与效果闸门生效。

func WithTTL

func WithTTL(kv store.KV, d time.Duration) store.KV

put 是"直接写入"的 KV 便捷封装(挂起日志无并发改写,不需读改写)。 WithTTL 给挂起后端套默认过期:调用方传 ttl<=0 的写入按 d 过期。 挂起记录天然该有寿命——无人应答的审批/提问在后端永久堆积,只涨不清。

Types

type ErrSuspended

type ErrSuspended struct {
	InteractionID string // 待答交互的确定性键
	Question      string // 已送达用户的问题
}

ErrSuspended 表示运行在交互点挂起,等待用户答复后重放。

func (*ErrSuspended) Error

func (e *ErrSuspended) Error() string

func (*ErrSuspended) TurnTerminal

func (e *ErrSuspended) TurnTerminal()

TurnTerminal 标记本错误为"轮次终止级":必须穿透工具错误转结果的 兜底 middleware(engine 侧按此接口放行),否则挂起信号会被吞掉。

type Journal

type Journal struct {
	// contains filtered or unexported fields
}

Journal 是一轮运行的挂起日志视图,由分发层创建并装入 ctx。 持有注入的 KV 后端,不感知具体实现。

func JournalFrom

func JournalFrom(ctx context.Context) *Journal

JournalFrom 取 ctx 中的挂起日志,可能为 nil。

func NewJournal

func NewJournal(kv store.KV, turnID string) *Journal

NewJournal 创建某一轮(turnID 恢复时必须与首跑一致)的日志视图。

func (*Journal) BeginEffect

func (j *Journal) BeginEffect(ctx context.Context, capKey, argsJSON string) error

BeginEffect 在执行 mutating 能力**之前**落"已开始"标记:此写失败则拒绝 执行(副作用尚未发生,失败安全)——这是效果日志幂等保证的前置台账。

func (*Journal) CompleteTurn

func (j *Journal) CompleteTurn(ctx context.Context)

CompleteTurn 在一轮成功结束后清理该轮的全部日志。

func (*Journal) Effect

func (j *Journal) Effect(ctx context.Context, capKey, argsJSON string) (string, bool)

Effect 查效果日志。命中哨兵时以"不可自动重试"的说明文本返回(ok=true, 挡住重放路径的再执行)。

func (*Journal) SaveEffect

func (j *Journal) SaveEffect(ctx context.Context, capKey, argsJSON, result string)

SaveEffect 把"已开始"标记覆盖为真实结果。写失败不能吞:标记会留在台账里, 后续重放命中哨兵、拒绝自动再执行(见 Effect)——宁可要求人工确认,也不 二次执行已审批的 mutating 操作。此处只能留痕。

func (*Journal) TurnID

func (j *Journal) TurnID() string

TurnID 返回本轮标识。

type Notify

type Notify func(ctx context.Context, question string) error

Notify 把挂起的问题送达用户(发进 IM 会话等),由分发层提供。

type PendingTurn

type PendingTurn struct {
	TurnID    string `json:"turn_id"`
	Input     string `json:"input"`
	WaitingID string `json:"waiting_id"` // 挂起时等待的交互键
}

PendingTurn 是一条挂起中的轮次记录。

func TakePendingTurn

func TakePendingTurn(ctx context.Context, kv store.KV, sessionKey string) (PendingTurn, bool, error)

TakePendingTurn 取出并删除会话的挂起轮次(答案到达时的恢复入口)。 认领经后端原子读改写完成(读到即删,mutate 返回 nil = 删除):Get 后再 Delete 的两步认领在多副本下会让同一挂起轮被两个副本各认领一次、双重放 ——重放里的 mutating 操作随之竞态。损坏的记录也在同一原子操作里消费掉 (否则它永远留在键上,该会话每条消息都撞同一错误,砖死)。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL