为 FastGPT 新增、修改或审查自动系统升级脚本及其注册信息。涉及系统迁移、升级任务、启动迁移、migration registry、checkpoint、全量重跑、阻塞升级、进度或失败数据时使用;普通业务更新和未接入自动升级框架的一次性手工清洗不使用。
复制下面这句话,粘贴给 Claude Code、Codex、Cursor 等 AI 编程工具,它会读取安装说明并在你确认后完成安装。
请阅读 https://ai.atlankj.com/install/asset/gh-system-migration-development-b008081854cb ,按照其中的说明把「system-migration-development」安装到你(当前 AI 工具)中。执行前先告诉我将运行的命令和写入的位置,等我确认。
查看 AI 将读取的安装说明正在读取 GitHub 原文…
内容来自 GitHub 原始文件,由原作者维护。在 GitHub 查看
系统升级任务属于 App 部署生命周期能力。框架负责顺序、状态、lease、并发互斥、重试入口和最终状态;脚本只负责可重复执行的业务迁移、进度、checkpoint,以及与阻塞类型匹配的错误报告方式。
开始前先查看当前实现,不能凭本 Skill 猜测已经变化的 Context 或目录结构:
projects/app/src/migration/registry.tsprojects/app/src/migration/runner.tspackages/global/migration/constants.tspackages/global/migration/schema.tsprojects/app/src/migration/tasks/README.md如果这些路径正在迁移,以仓库中 systemMigrations 和 SystemMigrationContext 的实际定义为准。迁移执行框架和任务实现收敛到 projects/app/src/migration;需要被 App 前后端共同使用的状态枚举、Zod Schema 和 API 类型放在 packages/global/migration。
先明确以下契约;存在会改变数据安全或启动行为的缺失信息时,向用户确认后再编码:
YYYYMMDD_short_semantic_name,以及首次发布版本。$setOnInsert、compare-and-set 或事务性全量重建。不要用“目标表存在”“目标表非空”或当前数据形态替代任务状态。是否需要执行只能由静态注册表和迁移状态决定。
blockStartup、onFailure 和函数语义不得修改、删除或复用;修复已发布迁移时追加新任务。| 状态 | 谁负责写入 | 触发条件 |
|---|---|---|
pending | 框架 | 首次初始化,或管理员将非阻塞失败任务恢复为待执行 |
running | Runner | 原子获得 lease,并生成新的 runId |
failed | Runner / context.fail | 脚本明确报告失败,或普通异常被 Runner 捕获 |
succeeded | Runner | 脚本正常返回且当前 runId 仍持有有效 lease |
脚本禁止直接操作迁移状态表和错误数据表,也不得主动设置 pending、running、failed 或 succeeded。所有运行状态写入必须经过 Context,让框架统一执行 runId fencing 和输入校验。
context.reportProgress(...):按注册表声明的阶段 key 更新该阶段快照。进入阶段时上报 running,完成后上报 succeeded;分批任务按合理频率更新 current/total,不要每条数据写一次。脚本不得主动上报 failed。context.getCheckpoint(schema):读取并用任务自有 Zod Schema 校验断点。仅分批任务使用。context.getFailedRecords():仅供非阻塞任务读取上次失败留下的坏数据。若任务曾跳过坏数据并把 checkpoint 推进到其后,重试时必须先处理这些记录;阻塞任务调用会被 Context 拒绝。context.reportFailedRecords(records):仅供非阻塞任务按批替换“当前完整未解决错误快照”。业务批次提交后应先上报错误快照,再推进 checkpoint;替换语义保证批次重放不会重复追加同一错误。阻塞任务调用会被 Context 拒绝。context.saveCheckpoint(value):只在一个幂等批次的业务事务完整提交、错误快照成功持久化并校验后保存。禁止先保存 checkpoint 再写业务数据或上报该批错误。context.assertActive():确认当前 runId 仍持有 lease。每个业务写入批次前必须调用;全量任务至少在关键事务前及事务后的后续阶段前调用。context.fail(...):保存可预期的结构化错误及最终错误快照,并终止本次执行。主要供需要在管理页面排障和重试的非阻塞任务使用;不要在调用后继续业务逻辑。阻塞任务通过该方法携带 failedRecords 会被拒绝。context.logger:记录诊断信息,框架会附加 migrationId、runId 和 runnerId。日志不能替代进度或结构化失败。context.signal:长计算或可取消 I/O 应响应中止信号。正常返回表示脚本认为业务迁移和完成校验均已成功,由 Runner 标记 succeeded 并清理该任务的错误明细。任务可以返回有限标量的业务参数对象;Runner 校验后把参数与 succeeded 原子写入,列表接口再从静态注册表取得 resultKey 组装展示结果。nameKey、descriptionKey、resultKey 和阶段 labelKey 必须在注册表中使用 i18nT(...) 声明,禁止把 i18n key 写入 Mongo。不要自行调用完成状态更新,也不要用最后一条 progress 代替最终结果。
普通 throw 也会进入 failed,Runner 会把错误归属到当前 running 阶段,并保留任务之前通过 reportFailedRecords 上报的最新快照。只有 context.fail 显式携带 failedRecords(包括空数组)时才替换或清空旧快照。非阻塞任务的已知数据问题应维护完整未解决错误快照:处理中按批调用 context.reportFailedRecords,扫描结束仍有异常时再调用 context.fail 写入相同最终快照。错误对象只保存原始 message,不得携带 i18n key 或模板参数;每条错误数据必须包含已声明的 stageKey,只保存必要 ID 和原因,不复制原文档。框架按阶段记录异常数量,管理员从对应阶段按需打开详情。阻塞任务失败时管理页面本身不可用,应通过 context.logger 输出必要诊断后抛出异常;Context 会拒绝其读写错误明细,Runner 只把多节点协调所需的最小 lastError 写入状态表。
任务一旦获得新 runId,无论入口是管理员重置还是过期 lease 接管,都使用同一恢复策略:保留 checkpoint、progress 和最近错误;非阻塞任务还会保留供修复使用的错误明细。但触发条件不同:running 的 lease 过期可自动接管,阻塞 failed 在 owner 重启、lease 过期后可接管,非阻塞 failed 必须由管理员重置为 pending。脚本如何恢复由发布时选定的策略决定。
适用于数据量较大、执行时间不可控、无法在一个短事务内完成,或需要跳过坏数据继续扫描的任务。
每次执行必须覆盖三种输入状态:
推荐循环:
读取并校验 checkpoint
读取 failedRecords,建立完整未解决错误快照并优先重试
while 还有数据:
assertActive
按稳定游标读取下一批
在业务事务中执行幂等写入
校验该批结果并提交事务
如果错误快照变化,reportFailedRecords(完整未解决错误快照)
saveCheckpoint
reportProgress
执行全局完成校验
如果仍有错误,fail(包含相同最终错误快照)
reportProgress(completed)
return
关键约束:
_id 或其他不可变、唯一且有索引的游标;不要使用 offset。reportFailedRecords 接收的是完整快照而不是新增项;不得逐条 append,也不得只上报当前批次,否则会覆盖之前仍未解决的错误。context.fail({ failedRecords }),其中 failedRecords 与最近一次上报的完整快照一致。仅适用于数据量确定较小、资源消耗有上界、结果由权威源确定,且整次写入可以保持原子或安全幂等的任务。
推荐流程:
reportProgress(started)
读取完整权威源
在修改目标前完成全部转换、去重和校验
assertActive
原子写入或确定性覆盖完整结果
assertActive
刷新缓存并执行完成校验
reportProgress(completed)
return
关键约束:
blockStartup 只决定节点 readiness,onFailure 只决定失败后是否暂停后续队列;所有任务仍严格按注册表顺序单线程执行。
reportProgress 保存最新快照并同步输出阶段日志;具体错误诊断写终端日志,不写 failedRecords。状态表中的最小 lastError 仅用于跨节点观察失败事实,不承担错误日志存储职责。onFailure: 'continue' 只允许相互独立的非阻塞任务使用:当前任务保持 failed 且等待管理员重试,Runner 可以跳过它继续后续任务;stop 则暂停后续队列。onFailure: 'stop' 的非阻塞任务仍是启动前置条件;continue 任务失败后允许后续阻塞任务推进,因此必须确认二者没有成功依赖。迁移执行框架、静态注册表、Mongo Schema、服务端执行逻辑和任务集中在 App;前后端公共契约位于 global:
packages/global/migration/
├── constants.ts
└── schema.ts
projects/app/src/migration/
├── constants.ts
├── registry.ts
├── runner.ts
├── entity.ts
├── service.ts
├── mongoSchema.ts
├── utils.ts
└── tasks/
├── README.md
└── <migration-id>/
├── index.ts
├── service.ts
└── utils.ts
index.ts 只负责任务编排、Context 调用和进度阶段。packages/global/migration 只保存前后端共享的状态枚举、有限输入 Schema 和 API 类型,不放任务实现、Mongo Model 或 Runner。progressSteps: [{ key, labelKey }];key 是永久稳定的机器标识,labelKey 放在 client-only system_migration i18n namespace,不写入 Mongo。packages/global 或 packages/service。pages/api、pages/config,但必须是调用 migration service 的薄入口,不承载迁移逻辑。i18nT(...) 保存稳定的 name、description、result 和 progress label key。message。projects/app/test/migration/ 下并镜像源码子路径。新增任务至少验证与其恢复策略相关的真实不变量,不写只匹配文案的测试。
通用场景:
running -> succeeded 上报;任务返回前所有声明阶段都已成功,阶段异常和错误数据使用正确的 stageKey。blockStartup 和 onFailure 符合数据依赖。分批任务额外验证:
getFailedRecords、reportFailedRecords 或通过 fail 携带 failedRecords 时会被 Context 拒绝。全量任务额外验证:
只运行覆盖改动范围的局部测试、App typecheck、相关 ESLint 和 git diff --check。用户最终验收前不主动运行全量测试。若修改 API 路由或入参,继续遵守 api-development Skill;若新增单元测试,继续遵守 test-case Skill。
lastError,没有调用错误明细能力。