Workspace Transaction Model#
Perago 的 workspace transaction 是一个由 runtime 执行的 TCC-inspired 发布模型。它把任务函数限制在 attempt-local workspace 内,让 worker runtime 负责 LakeFS staging、发布 fence、目标 branch merge、Conductor result 和清理。
这个模型来自 ADR-0001,目的是在不要求任务作者实现事务回调、不依赖 LakeFS Enterprise-only 功能、也不引入外部事务协调器的前提下,让 workspace task 的发布边界可解释、可重试、可排查。
设计目标#
Perago 的事务模型解决的是 workspace task attempt 的发布安全问题,而不是所有分布式一致性问题:
目标 |
Perago 的做法 |
|---|---|
任务函数保持简单 |
task body 只接收本机 |
未确认写入不污染目标 branch |
所有写入先进入 execution-scoped staging branch。 |
stale attempt 不应继续发布 |
runtime 在 stage 前和 publish 前各执行一次 attempt fence。 |
branch advancement 可分类 |
confirm commit 写入 Perago metadata,publish fence 只接受已知安全状态。 |
不确定状态 fail closed |
无法用 Conductor attempt 状态和 LakeFS metadata 分类时,让当前 attempt 失败。 |
Perago 不把 workspace transaction 暴露成用户 API。任务作者不需要写 try、confirm 或 cancel 函数,也不需要在业务代码里直接操作 staging branch。
TCC 映射#
Perago 借用 TCC 的阶段名称,但阶段由 runtime 完成:
阶段 |
Runtime 行为 |
成功产物 |
|---|---|---|
Try |
从 input |
带 |
Confirm |
通过 attempt fence 和 publish fence 后,把 staging branch squash merge 到目标 branch。 |
带 |
Cancel |
attempt 失败、stale 或完成后清理 staging branch 和本机 attempt-local workspace。 |
清理日志;不会回滚已成功 merge 的目标 branch。 |
这不是 XA、AT 或 Saga:
模型 |
为什么不是 Perago MVP 的主模型 |
|---|---|
XA |
Conductor task completion 与 LakeFS branch merge 不属于同一个 XA resource manager。 |
AT |
Perago 没有透明代理业务写入,也没有可自动回滚 LakeFS commit 的 undo log。 |
Saga |
Saga 要求业务补偿或恢复动作,和 Perago 让 task body 保持普通 typed Python 函数的目标冲突。 |
Attempt fence#
Attempt fence 防止已经不是当前 in-progress attempt 的 worker 继续推进 workspace。Perago 在两个位置检查它:
task body 和 post guardrails 成功之后、stage 之前。
stage 成功之后、publish 之前。
fresh attempt 必须仍然匹配已 poll 到的 Conductor attempt:status 是 IN_PROGRESS,workflow_instance_id、task_id 和 retry_count 都没有变化。任一条件失败,attempt 返回普通 FAILED,runtime 继续尝试清理 staging branch 和本机 workspace。
双 fence 的原因是 stage 本身可能耗时。第一次 fence 避免失效 attempt 上传 staging workspace;第二次 fence 避免 stage 完成后已经失效的 attempt 继续 merge 目标 branch。
Publish fence#
Publish fence 判断目标 branch 当前 head 是否仍可被本次 attempt 推进。MVP 接受两种状态:
目标 branch 状态 |
行为 |
|---|---|
current head 等于 input |
以 input ref 作为 publish base,允许发布。 |
current head 是同一个 |
允许继续发布,并在 metadata 里记录 |
其他 branch advancement 都会触发 PublishFenceError。这通常表示目标 branch 被其他 workflow step、其他 workflow instance 或非 Perago 写入推进;runtime 不发布 workspace output,让 Conductor 按普通失败路径处理。
runtime 会沿 first-parent history 从 current head 回溯到 input workspace.ref,但扫描最多 1024 个 commits。超过这个范围,或 history 已经不包含 input ref,都会被视为无法分类的 branch advancement 并 fail closed。
这个 publish fence 是 client-side soft fence。它在 merge 前读取和判断目标 branch head,但不是 LakeFS server-side compare-and-swap,因此不能证明严格 exactly-once publication。
Metadata#
Confirm commit metadata 是 retry 分类和人工排查的事实来源:
Metadata |
用途 |
|---|---|
|
区分 try commit 与 confirm commit。 |
|
标识同一个 workflow step,retry attempt 共享这个 key。 |
|
标识当前 Conductor attempt。 |
|
辅助定位 retry attempt。 |
|
记录本轮 attempt 读取的不可变输入 ref。 |
|
记录被推进的 LakeFS branch。 |
|
记录 task 声明的 workspace prefix。 |
|
记录被 merge 的 staging branch。 |
|
记录被 merge 的 staging commit。 |
|
记录 publish fence 选择的发布基准。 |
|
记录同一 logical task 之前推进过的 commit;没有则为空字符串。 |
如果 worker 在 LakeFS merge 成功后、Conductor completion 前死亡,Perago 不从 LakeFS metadata 恢复旧 workflow 状态,也不补发 Conductor completion。Conductor 会按自己的 timeout/fail/retry 语义处理;后续 execution 使用新的 staging branch。publish fence 仍会用 metadata 区分“同一 logical task 的前一次发布”和“无关 branch advancement”,但这不是 workflow recovery。
故障与恢复边界#
Perago 的 MVP 事务边界是 operationally bounded,而不是 exactly-once 证明:
场景 |
行为 |
|---|---|
pre guardrail 失败 |
返回 |
task body、post guardrail、download、stage 失败 |
返回普通 |
attempt fence 失败 |
返回普通 |
publish fence 或 merge 失败 |
返回普通 |
cleanup 失败 |
保留原始 result,只写日志。 |
merge 已成功但 worker 死亡 |
不补发旧 completion;由 Conductor timeout/fail/retry,后续 execution 用 publish fence 分类目标 branch 状态。 |
Fail closed 的恢复方式不是在原 attempt 内猜测补偿动作,也不是从 LakeFS 反推 Conductor 状态,而是让 Conductor 按失败或重试策略推进;需要人工恢复时,从当前 protected branch head 发起新的工作流。
运行时假设#
这个模型依赖以下运营约束:
workspace 写入 workflow 在定义上保持串行,不允许并行分支同时写同一个 LakeFS target branch。
同一时间只有一个活跃 workflow instance 写入给定 workspace branch。
target branch 应由 LakeFS branch protection 保护,workspace 更新只通过 runtime merge 进入。
PublishBudget应使用真实 LakeFS merge 观测值设置 timeout、heartbeat 和 shutdown grace,而不是作为 changed-object quota。LakeFS Community hook 可以作为未来 hard fence 候选,但必须先用部署版本的集成测试证明其语义;当前 runtime 不依赖它,也不把 LakeFS/Conductor 做成跨系统事务。
更细的执行顺序见 Workspace Publication,LakeFS object 同步规则见 LakeFS Runtime。