Fago 文档 Fago 文档
首页
快速开始
后端手册
前端手册
规划备查
文档维护
首页
快速开始
后端手册
前端手册
规划备查
文档维护
  • 快速开始

    • 简介
    • 功能列表
    • 快速启动(后端)
    • 快速启动(前端)
    • 技术选型
    • 项目结构
    • 接口与错误码
  • 后端手册

    • 配置与环境
    • 登录与会话
    • 功能权限与菜单
    • 数据权限
    • 用户、部门、岗位与角色
    • 租户与安全策略
    • 异常处理与错误码
    • 参数、分页与响应
    • 数据库迁移
    • 日志、脱敏与请求加密
    • 平台租户与套餐
    • fago-cli 常用命令
    • 发布验证与恢复演练
    • 字典与参数配置
    • 文件与对象存储
    • 站内通知与执行恢复
    • 定时任务与运行恢复
    • 可靠消息后端与积压观测
    • 身份客户端与设备会话
    • 会员认证与账号管理
    • 服务账号与 scope
    • OIDC 提供方与外部绑定
    • 原生 SSO 验收客户端
    • 账号认证模式
    • 工作流 API 与运行目录
  • 前端手册

    • 本地启动
    • 菜单与路由
    • 请求合同
    • 页面与按钮权限
    • 浏览器单点登录
    • 审批中心与表单发起
    • 工作流定义与运行管理
  • 规划备查

    • Fago:架构与实施方案
    • 总体架构
    • 身份、权限与租户设计
    • Vben 5 前端与 API 合同
    • 数据库与消息后端适配
    • 纯 Go 通用工作流:文件、文档与业务流程
    • 核心数据模型
    • 分期、工作包与验收
    • 架构决策与风险
    • 参考来源与基线
    • 网络安全等级保护二级合规要求
    • M0 实施与验收
    • M1 身份与导航实施及验收
    • 项目配置、API 内容加密与敏感数据脱敏
    • M2 系统管理实施记录
    • M3 平台与 SaaS 实施记录
    • fago-cli 功能规划
    • 生产传输层 WARN 变更范围(2026-10-23)
    • M4 发布实施与验收
    • M4 加固检查归档(本地工程环境)
    • M5 通用平台与身份实施
    • M6 R3.1 正式工作流核心与基础审批
目录

定时任务与运行恢复

# 定时任务与运行恢复

# 目的

配置仅使用 Cron 的持久任务,查看实际触发点、运行与认领历史,并在失败后恢复原运行。租户任务内置「受理站内通知」;平台任务内置「平台基础设施目录统计」、「按租户拆分基础设施统计」和「维护统计结果」。计划保存成功只表示配置已提交,运行完成的含义由处理器决定。

平台目录统计完成后可以查看计数结果。按租户拆分的父运行完成只表示各目标子运行已持久受理,每个租户的成功、失败和恢复都在「租户子运行」中查看。通知任务完成表示通知已受理,实际送达继续查 站内通知。

# 前置条件

显式迁移到当前 schema v29,再启动匹配的 API、worker 和前端。迁移不自动启用任何平台任务;旧非 Cron 计划会停用待重新配置,见本页「历史计划升级」。在外层仓库运行,数据库和 Redis 参数由本机环境配置提供:

bash scripts/fago.sh migrate
bash scripts/fago.sh api
# 在另一个终端启动;只启动API不会调度或执行业务。
bash scripts/fago.sh worker

成功时 API 就绪检查通过,worker 启动租户任务、平台父任务和租户子运行循环。对象存储可以关闭;连接、schema 或必要依赖不符时启动失败,不降级为内存执行。

租户套餐必须开通 infra.jobs,通知处理器另需 infra.notifications。租户角色按需授予 infra:job:read/create/update/delete/run/replay;准备通知内容另需 infra:notification:send,页面选择模板需 infra:template:read。平台使用独立的 platform:infra:job:read/create/update/delete/run/replay;选择租户目标另需当前 platform:tenant:read。子运行执行时目标套餐必须仍有 infra.jobs 和 infra.configuration,租户必须启用且未到期。平台权限不能替代目标当前能力检查。

# 步骤与规则

# 1. 预览当前 Cron

打开租户「基础设施 → 定时任务」或平台「平台基础设施 → 平台系统任务」。填写名称、编码、处理器、准入起点、五段表达式、IANA 时区和错过策略,先点击「校验并预览执行时间」。页面显示服务端计算的未来最多五次时间;字段变化、预览失败或旧预览晚到都会使保存资格失效。

以下为开发环境明文预览。startAt 示例为 2030-01-01 UTC,只用于演示;实际使用本次需要的 UTC 毫秒准入起点。生产走统一 JWE,解密后的业务结构相同:

POST /api/admin/v1/infra/jobs/preview
Origin: http://127.0.0.1:5174
X-App-Request: admin
Authorization: Bearer <操作者提供的access>
Content-Type: application/json

{"kind":"cron","startAt":1893456000000,"cronExpression":"*/5 * * * *","timeZone":"Asia/Shanghai","misfirePolicy":"coalesce"}

成功响应中 times 是严格递增的 UTC 毫秒点,页面按响应的时区显示。平台预览使用 /api/platform/v1/infra/jobs/preview 和 X-App-Request: platform。

{"code":0,"data":{"times":[1893456000000,1893456300000,1893456600000,1893456900000,1893457200000],"timeZone":"Asia/Shanghai"},"message":"ok","requestId":"req_preview"}

Cron 格式为「分 时 日 月 周」,不接受秒、年、@every、描述符或表达式中的时区覆盖。每五分钟使用 */5 * * * *,每天凌晨两点使用 0 2 * * *,每周一九点使用 0 9 * * MON。这是日历边界计算,不是从上次业务完成后再等待一段时间。夏令时缺失分钟跳过,回拨重复分钟分别形成不同 UTC 触发点。

# 2. 保存租户通知计划

先准备启用的同租户通知模板与有效收件账号。创建时提交完整变量,服务在当前权限事务内渲染并保存私有内容快照;管理接口不会返回正文、原变量、摘要、租约 token 或运行随机键。

POST /api/admin/v1/infra/jobs
Origin: http://127.0.0.1:5174
X-App-Request: admin
Authorization: Bearer <操作者提供的access>
Content-Type: application/json

{
  "code":"reminder.daily","name":"每日提醒","handler":"notification.inapp",
  "schedule":{"kind":"cron","startAt":1893456000000,"cronExpression":"0 9 * * *","timeZone":"Asia/Shanghai","misfirePolicy":"coalesce"},
  "status":"enabled","version":0,
  "payload":{"templateId":"10","templateVersion":1,"recipientId":"20","variables":{"name":"同事"}}
}

variables 必须与所选模板一致;示例中的模板及账号 ID 需换成本租户真实资源。成功的计划 DTO 如下,实际 ID 与 nextDue 由服务计算:

{"code":0,"data":{"id":"30","code":"reminder.daily","name":"每日提醒","handler":"notification.inapp","schedule":{"kind":"cron","startAt":1893456000000,"cronExpression":"0 9 * * *","timeZone":"Asia/Shanghai","misfirePolicy":"coalesce"},"needsConfiguration":false,"status":"enabled","version":1,"nextDue":1893459600000},"message":"ok","requestId":"req_create"}

编码与处理器创建后不可变。普通编辑保留未返回页面的私有内容;只有勾选重新配置内容才发送新 payload 并重新检查模板版本、发送权限和收件状态。更新用 PUT /jobs/{id},携带当前正数 version;省略或 null 载荷保留原快照。后台推进游标不改变配置版本。

# 3. 保存平台统计与租户拆分计划

平台目录统计使用 handler: "platform.infrastructure.snapshot" 与 payload: {}。按租户统计使用下列固定处理器,目标来自平台租户管理中的规范 ID,最多100个且不重复。编辑已有计划默认保留原目标;只有显式重新选择才替换未来父运行的目标快照。

POST /api/platform/v1/infra/jobs
Origin: http://127.0.0.1:5174
X-App-Request: platform
Authorization: Bearer <平台操作者提供的access>
Content-Type: application/json

{
  "code":"statistics.tenants","name":"租户目录统计","handler":"tenant.infrastructure.snapshot",
  "schedule":{"kind":"cron","startAt":1893456000000,"cronExpression":"0 2 * * *","timeZone":"Asia/Shanghai","misfirePolicy":"skip"},
  "status":"enabled","payload":{"tenantIds":["2","3"]}
}

保存成功后点击「执行一次」可以立即验证,不必等待准入起点。平台父事务只受理子集合,不获取全部租户锁;子运行使用真实租户 ID,分别检查当前状态、到期和能力,分别限流、重试与记录历史。某个租户不可用、队列满或暂时写入失败,不回滚其他租户已经完成的业务。

平台页面通过以下专用接口读取子历史,不能将相同数字的子运行 ID 送到父运行接口:

GET /api/platform/v1/infra/jobs/30/tenant-runs?pageNo=1&pageSize=20
Origin: http://127.0.0.1:5174
X-App-Request: platform
Authorization: Bearer <平台操作者提供的access>

GET /api/platform/v1/infra/tenant-job-runs/31/attempts?pageNo=1&pageSize=20
Origin: http://127.0.0.1:5174
X-App-Request: platform
Authorization: Bearer <平台操作者提供的access>

子运行 DTO 额外包含 tenantId 与 parentRunId,触发来源是 platform。计数结果分别由 GET /api/platform/v1/infra/snapshots/{id} 和 GET /api/platform/v1/infra/tenant-snapshots/{id} 读取;页面点击「统计结果」。两者只返回数量、目标和生成时间,没有参数原值。

# 平台全局维护

固定处理器 platform.infrastructure.maintenance 使用 payload: {},标签明确显示「清理90天前,每表100条」。它分批清理平台及租户目录统计结果,保留计划、运行、attempt、在线审计和业务参数。默认不会创建或启用维护计划,管理员需明确选择该处理器和Cron。

{"code":"statistics.maintenance","name":"统计结果保留期维护","handler":"platform.infrastructure.maintenance","schedule":{"kind":"cron","startAt":1893456000000,"cronExpression":"0 3 * * *","timeZone":"Asia/Shanghai","misfirePolicy":"skip"},"status":"enabled","payload":{}}

将上述正文提交到同一 POST /api/platform/v1/infra/jobs,认证/Origin/来源头同前。运行完成后点击「维护结果」,GET /api/platform/v1/infra/maintenance-results/{id} 返回实际 cutoffAt、platformDeleted、tenantDeleted 和 createdAt。每表最多100条,成功后的新命令可继续下一批;同键重试原已完成命令不会再清理一批。清理、结果和运行完成同事务,失败整体回滚。90天前的统计详情可能返回404,原任务历史仍可查看。

# 4. 人工命令与原死信恢复

「执行一次」是独立幂等命令,保留为手动操作,不是一次性调度类型,也不推进定时游标。页面在同一确认框失败重试时保留原键和计划版本。关闭后重新打开代表新执行意图;结果不确定时先查原运行,不能换键猜测失败。

POST /api/platform/v1/infra/jobs/30/run
Origin: http://127.0.0.1:5174
X-App-Request: platform
Authorization: Bearer <平台操作者提供的access>
Content-Type: application/json

{"version":1,"idempotencyKey":"statistics_manual_0001"}

同计划、操作者、键及版本返回原运行,即使计划随后修改、停用或删除;仍要通过当前认证和执行权限。同键换版本返回 409002。键为16–64个小写字母、数字、下划线或短横线。

死信恢复只恢复原 dead,要求当前计划启用、准入代次一致、尚无已受理资源,并同时核对计划与运行版本。恢复保留原身份和载荷、保留旧历史,重置本轮次数及24小时窗口;完成、取消或旧代次不能恢复。子运行使用独立恢复路径:

POST /api/platform/v1/infra/tenant-job-runs/31/replay
Origin: http://127.0.0.1:5174
X-App-Request: platform
Authorization: Bearer <平台操作者提供的access>
Content-Type: application/json

{"jobVersion":2,"runVersion":5}

成功返回 {"code":0,"data":null,"message":"ok","requestId":"req_replay"}。父运行恢复使用 /job-runs/{id}/replay;租户任务根路径改为 /api/admin/v1/infra。通知投递失败应恢复原通知,不能重新执行已经完成的任务生成第二份通知。

# 参数与执行约束

参数或限制 规则
schedule.kind 只能为 cron;旧 once、interval 和 intervalSeconds 不再是输入合同
startAt UTC毫秒,1至2100-01-01;新起点不能早于当前60秒;已保存起点可保留
cronExpression / timeZone 五段、最多128字节;独立IANA时区最多64字节,拒绝 Local
misfirePolicy 默认 coalesce:执行最早到期点一次再推进未来;skip:超过一分钟抖动窗口则跳过;catch_up:只补最近24小时,每计划每轮最多一条
计划容量 每租户最多1000个有效计划;平台父计划同样有界
平台目标 每份快照1–100个;父受理失败整份回滚,不能只留下半组子集合
租户子运行配额 每租户最多100个活跃子运行;满目标保留 429001 死信,其他目标继续;恢复前也检查容量
租户子运行速率 每租户滚动一分钟最多60次认领,含失败历史;限流只推迟,不消耗业务重试次数
租约与截止 租约30秒、本地业务事务最多10秒;单批最多100、正式循环每批20;恢复窗口24小时
重试 本轮最多5次,临时故障按1/2/4/8/16秒退避;明确不可用目标保留各自失败历史
查询 pageNo/pageSize,每页最多100;计划按名称关键词,运行/历史不接受关键词或租户选择器

# 历史计划升级

v27 保留旧调度字段和所有运行历史,将非 Cron 计划停用、清零下一触发点,推进配置版本、游标版本和准入代次。页面显示「历史计划已停用,需配置 Cron」,响应 needsConfiguration: true 且省略 schedule。旧61秒等间隔无法通用等价转换为五段日历表达式,所以不自动改写原执行语义。

重新编辑并预览合法 Cron、显式启用后才生成未来运行;旧准入代次的未完成运行仍不能复活。停用/删除与执行通过计划锁竞争,已经先提交的业务不会被撤回。SQL历史持续保留,不通过删除历史来消除积压。

# 失败处理

格式错误、已删除的调度字段通常是 400001;非法 Cron、时区、目标或起点为 400002。目标不存在为 404001。版本冲突必须关闭编辑器、刷新并核对,不能自动换版本覆盖:

HTTP/1.1 409 Conflict
Content-Type: application/json

{"code":409001,"data":null,"message":"记录已变更,请重试","requestId":"req_conflict"}

403001 是当前权限/目标能力拒绝;403004 是来源校验失败;409003 是状态或容量冲突;429001 可等待限额释放后重试。数据库/审计依赖故障返回 503001,业务与审计回滚。超时或提交结果未知先查询原运行,不直接换键。生产错误也使用JWE,解密后仍只含公开提示和稳定码。

# 边界

Cron库只计算日期,持久计划/运行、去重、租约、fencing和恢复由同库执行引擎负责。平台父表不含租户外键,不使用虚假零租户;子运行只从已受理父运行产生,并在业务事务中获取真实租户锁。在线操作审计有真实平台操作者,后台不冒充操作者,以运行/attempt保留执行历史。

处理器只由代码白名单注册,最多32个,必须遵守传入context并只使用传入事务;不支持用户脚本、任意URL、SQL、命令、动态处理器或在回调进行网络副作用。新增业务处理器仍须单独实现授权和幂等。工作流定时器、自动SQL历史归档、生产容量/恢复和达梦v29尚未认证,不因本页可以管理Cron就宣称这些能力已完成。

# 关联

完整合同见仓库 api/openapi.yaml。迁移见 数据库迁移,平台参数见 字典与参数配置,通知见 站内通知,实际检查及未认证边界见 M5增量实施记录。

最后更新: 2026/10/29 08:15:25
站内通知与执行恢复
可靠消息后端与积压观测

← 站内通知与执行恢复 可靠消息后端与积压观测→

Theme by Vdoing | Copyright © 2026-2026 Fago 项目文档
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式