Documentation
¶
Overview ¶
Package suspend 实现挂起/恢复的持久化:ask_user 与审批等待不再靠 进程内 goroutine 阻塞——飞书审批常常跨小时甚至隔天,占着 goroutine 等、进程一重启全丢,撑不住真实使用。
机制是"卸载重放"(durable execution lite):
- 挂起:交互点(Ask/Approve)查不到已记录的答案时,持久化待答 记录并返回 ErrSuspended,整轮调用栈退干净,进程不持有任何状态;
- 恢复:用户的答案(可能在进程重启之后)写入交互日志,原输入 重跑该轮——交互点按确定性键命中日志直接返回答案,越过挂起点;
- 幂等:mutating 工具的执行结果随轮记入效果日志,重放时命中即 返回记录结果、不二次执行(只读工具与模型调用照常重跑,安全)。
重放路径若与首次运行分叉(模型换了措辞/换了路径),交互键不再命中, 退化为重新提问——多问一次,但不会答非所问,失败模式是安全的。
Index ¶
- Constants
- func AnswerPending(ctx context.Context, kv store.KV, interactionID, answer string) error
- func DurableEffects(caps []capability.Capability) []capability.Capability
- func Interactor(j *Journal, notify Notify) runctx.Interactor
- func IsAffirmative(reply string) bool
- func NewTurnID() string
- func SavePendingTurn(ctx context.Context, kv store.KV, sessionKey string, rec PendingTurn) error
- func WithJournal(ctx context.Context, j *Journal) context.Context
- func WithTTL(kv store.KV, d time.Duration) store.KV
- type ErrSuspended
- type Journal
- func (j *Journal) BeginEffect(ctx context.Context, capKey, argsJSON string) error
- func (j *Journal) CompleteTurn(ctx context.Context)
- func (j *Journal) Effect(ctx context.Context, capKey, argsJSON string) (string, bool)
- func (j *Journal) SaveEffect(ctx context.Context, capKey, argsJSON, result string)
- func (j *Journal) TurnID() string
- type Notify
- type PendingTurn
Constants ¶
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 ¶
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 ¶
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 SavePendingTurn ¶
SavePendingTurn 持久化挂起中的轮次(同会话同时只有一条)。
func WithJournal ¶
WithJournal 把挂起日志装入 ctx,对下游交互与效果闸门生效。
Types ¶
type ErrSuspended ¶
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 NewJournal ¶
NewJournal 创建某一轮(turnID 恢复时必须与首跑一致)的日志视图。
func (*Journal) BeginEffect ¶
BeginEffect 在执行 mutating 能力**之前**落"已开始"标记:此写失败则拒绝 执行(副作用尚未发生,失败安全)——这是效果日志幂等保证的前置台账。
func (*Journal) CompleteTurn ¶
CompleteTurn 在一轮成功结束后清理该轮的全部日志。
func (*Journal) SaveEffect ¶
SaveEffect 把"已开始"标记覆盖为真实结果。写失败不能吞:标记会留在台账里, 后续重放命中哨兵、拒绝自动再执行(见 Effect)——宁可要求人工确认,也不 二次执行已审批的 mutating 操作。此处只能留痕。
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 操作随之竞态。损坏的记录也在同一原子操作里消费掉 (否则它永远留在键上,该会话每条消息都撞同一错误,砖死)。