Backstage Scaffolder Action Rollback(BEP-0006)解析:为任务失败提供回滚机制
2026/9/10 10:19:34 网站建设 项目流程

Backstage Scaffolder Action Rollback(BEP-0006)解析:为任务失败提供回滚机制

【免费下载链接】backstageBackstage is an open framework for building developer portals项目地址: https://gitcode.com/GitHub_Trending/ba/backstage

本文基于仓库内beps/0006-scaffolder-action-rollback/README.md(Backstage Enhancement Proposal 0006,状态 provisional)撰写,系统讲解 Backstage Scaffolder(软件模板引擎)中"Action 回滚"这一能力的设计动机、提案方案,并结合当前仓库源码梳理任务恢复(Task Recovery)机制的实现现状与落地路径。读完本文,你将理解:为什么需要为 Scaffolder Action 增加回滚能力、BEP 提案设计的 API 形态是什么、当前仓库中任务恢复/回滚相关的底层实现细节,以及该提案与现有代码之间的差距。

BEP 背景:为什么需要 Action 回滚

Backstage 的 Scaffolder 通过"模板 + 一系列步骤(steps)"的方式编排软件交付流水线,每个步骤调用一个模板 Action(例如创建仓库、推送分支、发布 GitHub 资源等)。当模板执行到中途某个步骤失败时,前面步骤已经产生的资源(仓库、分支、PR、文件等)往往已经部分落盘到外部系统,形成"半成品"。

在没有回滚能力之前,处理这类问题的唯一手段是人工手动清理这些部分创建的资源——这既耗时又容易遗漏。BEP-0006 的提出者(bnechyporenko@bol.com 与 benjaminl@spotify.com,归属@backstage/scaffolder-maintainers维护)正是希望用程序化的方式解决这一痛点:

Introducing the rollback to scaffolder actions provides the mean to come back to the initial state.

即:为 Scaffolder Action 引入回滚能力,让任务失败后能够回到初始状态

Goals(目标)

  • 扩展 Action 的 API,使其能够对失败的任务执行回滚(rollback);
  • 回滚必须是可选的(optional)——不是所有 Action 都被强制要求实现回滚逻辑。

Non-Goals(非目标)

  • 不会为所有内置 Action 都覆盖回滚功能。这意味着回滚是一个渐进式能力:先由部分 Action 实现,再逐步扩展。

Proposal:回滚在什么时机执行

BEP 明确指出回滚会在以下两种情形下被触发:

  1. 用户手动决定执行回滚操作——即用户在 UI 或 API 层面主动对失败任务发起回滚;
  2. 任务被恢复(recovered)且 TaskRecoverStrategy 被设置为'rollback'——即系统在自动恢复失败任务时,按照任务规格中声明的恢复策略,以"回滚"作为恢复手段。

这里引入了一个关键概念TaskRecoverStrategy(任务恢复策略)。需要特别说明的是:当前仓库中该策略的实际取值与 BEP 提案存在差异(详见下文"与现状的差距"一节)。

Design Details:Action API 的扩展形态

BEP 给出的核心设计是:在现有模板 Action 的创建函数createTemplateAction中,新增一个可选的rollback异步函数,与既有handler平级。提案中的示例代码如下:

const createPublishGitHubAction = createTemplateAction({ id: 'publish:github', async handler() {}, async rollback() {}, });

设计要点:

  • handler负责 Action 的正常执行逻辑(创建资源);
  • rollback负责在任务失败时撤销handler已产生的副作用(删除资源、关闭 PR、恢复分支等);
  • rollback可选属性——对于无法实现回滚或回滚无意义的 Action,可以直接省略,这正是"Rollback will be optional"目标的落地形态。

从语义上看,rollback的设计与handler保持对称:两者都接收相同的 Action 上下文(输入参数、工作目录、日志器等),因此回滚逻辑可以复用与执行逻辑相同的上下文信息。

仓库现状:任务恢复机制的源码级剖析

虽然 BEP-0006 目前仍是 provisional(暂定)状态、rollback函数尚未合入 Action API,但与之配套的任务恢复(Task Recovery)机制在当前仓库中已经相当成熟。理解这套机制,是评估 BEP 落地可行性的关键。

1. TaskRecoverStrategy 的类型定义

任务恢复策略定义在 plugins/scaffolder-common/src/TaskSpec.ts:

/** * none - not recover, let the task be marked as failed * startOver - do recover, start the execution of the task from the first step. */ export type TaskRecoverStrategy = 'none' | 'startOver'; export interface TaskRecovery { EXPERIMENTAL_strategy?: TaskRecoverStrategy; }
  • 'none'(默认值):不恢复,任务直接从processing状态标记为failed
  • 'startOver':恢复任务,从头开始重新执行所有步骤。

该策略通过任务规格上的EXPERIMENTAL_recovery字段(见 TaskSpec.ts)声明在 Template 中:

/** * How to recover the task after system restart or system crash. */ EXPERIMENTAL_recovery?: TaskRecovery;

注意:当前仓库中TaskRecoverStrategy只有'none' | 'startOver'两种取值,并没有 BEP 提案中提到的'rollback'。这正是该 BEP 尚未落地为代码的实证——提案中的"回滚式恢复"是startOver之外的第三种策略设想。

2. 任务恢复的开关与事件裁剪

plugins/scaffolder-backend/src/scaffolder/tasks/taskRecoveryHelper.ts 提供了两个核心函数:

  • isTaskRecoveryEnabled(config):判断自动恢复是否开启。读取scaffolder.taskRecovery.enabled,并向后兼容旧配置scaffolder.EXPERIMENTAL_recoverTasks,两者都未配置时默认false
  • trimEventsTillLastRecovery(events):当任务发生过'recovered'事件且恢复策略为'startOver'时,将事件列表裁剪到最近一次恢复之后,避免日志/事件展示被历史恢复过程污染。

3. 恢复循环与 Worker 执行

在 plugins/scaffolder-backend/src/scaffolder/tasks/TaskWorker.ts 中,任务恢复由 Worker 周期驱动:

async recoverTasks() { await this.options.taskBroker.recoverTasks?.(); } private async runTaskRecoveryLoop() { // ... await this.recoverTasks(); }

Worker 在启动后通过runTaskRecoveryLoop()定期调用taskBroker.recoverTasks(),而DatabaseTaskStoreStorageTaskBroker分别实现了对应的recoverTasks方法(见 DatabaseTaskStore.ts 与 StorageTaskBroker.ts)。在 DatabaseTaskStore.ts 中可以推断:是否将一个任务标记为可恢复,取决于recoverTasksEnabled配置与任务规格是否满足可恢复条件(isRecoverableTask(spec))。

4. 恢复相关的配置项

配置声明位于 plugins/scaffolder-backend/config.d.ts:

  • scaffolder.taskRecovery.enabled:是否启用自动任务恢复;
  • scaffolder.taskRecovery.staleTimeout:任务被视为"过期(stale)"并进入可恢复队列的等待时长;
  • 旧配置scaffolder.EXPERIMENTAL_recoverTasksEXPERIMENTAL_recoverTasksTimeout等已被标记为 deprecated,统一迁移到taskRecovery命名空间下。

5. 前端:OngoingTask 中的恢复交互

前端侧,任务执行页面 plugins/scaffolder/src/components/OngoingTask/OngoingTask.tsx 通过useTaskEventStream订阅任务事件流,并提供取消/恢复任务的交互入口(依赖taskCancelPermissiontaskCreatePermissiontaskReadPermission等权限控制)。这为 BEP 中"用户手动决定执行回滚"的交互场景提供了现成的承载页面——一旦rollback合入 Action API,这类页面即可扩展出"回滚"按钮。

与现状的差距:BEP 落地还差什么

对比 BEP 提案与仓库现状,可以明确以下差距:

维度BEP-0006 提案当前仓库现状
Action API 形态createTemplateAction新增可选rollback()plugins/scaffolder-node/src/actions/types.ts 中TemplateAction仅有handler,无rollback字段
恢复策略取值包含'rollback'plugins/scaffolder-common/src/TaskSpec.ts 中仅有'none' \| 'startOver'
内置 Action 覆盖逐步覆盖尚无任何内置 Action 提供回滚实现

也就是说,BEP-0006 是一份尚未实施的设计蓝图:任务恢复的基础设施(恢复开关、过期检测、Worker 循环、事件裁剪)已经就绪,但"Action 回滚"这一上层能力仍待实现。落地路径大致为:

  1. 在 plugins/scaffolder-node/src/actions/types.ts 的TemplateAction类型中增加可选的rollback字段;
  2. TaskRecoverStrategy中引入'rollback'取值(plugins/scaffolder-common/src/TaskSpec.ts),并让任务执行器在恢复时根据策略调用各步骤已执行 Action 的rollback
  3. 为部分内置 Action(如publish:githubpublish:gitlab等发布类 Action)编写回滚实现;
  4. 在前端任务页(OngoingTask.tsx)增加手动回滚入口。

Alternatives:备选方案

BEP 文档的 Alternatives 章节当前为占位状态(仅保留了说明性注释:应当记录"还考虑过哪些其他方案,以及为什么排除它们")。从既有实现可以推断,社区目前的恢复策略是startOver(从头重跑)而非"撤销式回滚"——两者本质差异在于:startOver需要模板本身具备幂等性以承受重复执行,而回滚则试图通过撤销副作用回归初始状态,对模板幂等性的要求更低,但对 Action 实现者提出了编写逆向逻辑的要求。这也是 BEP 选择"回滚可选、逐步覆盖"作为折中方案的原因。

总结

BEP-0006(Scaffolder Action Rollback)为 Backstage 模板引擎规划了一条从"人工清理半成品资源"走向"程序化回滚"的演进路径:通过在createTemplateAction中新增可选的rollback函数、并将'rollback'纳入任务恢复策略,让任务失败后既可以由用户手动触发回滚,也可以在自动恢复时按策略执行回滚。当前仓库已具备完整的任务恢复基础设施(恢复开关配置、过期检测、Worker 恢复循环、恢复事件裁剪),但 Action 级rollbackAPI 尚未合入——对于希望参与 Backstage 插件生态的开发者而言,这正是值得关注的扩展点与潜在贡献方向。

【免费下载链接】backstageBackstage is an open framework for building developer portals项目地址: https://gitcode.com/GitHub_Trending/ba/backstage

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询