feat: add durable schedule management and multi-node crash recovery
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# Orbit 生产验收与发布门槛
|
||||
|
||||
> 版本 0.2 · 2026-09-17。本文是全平台生产发布门槛。P0–P2 已积累阶段证据,见 [开发计划](08-development-plan.md) 与 [P2 验收](reports/phase-2.md);未覆盖的场景继续实施,尚无全平台生产验收或容量结论。
|
||||
> 版本 0.2 · 2026-09-17。本文是全平台生产发布门槛。P0–P2 已积累阶段证据,见 [开发计划](08-development-plan.md) 与 [P2 验收](reports/phase-2.md);P3 新增 [计划调度证据](reports/phase-3-schedules.md)。未覆盖的场景继续实施,尚无全平台生产验收或容量结论。
|
||||
|
||||
## 1. 验收对象与证据
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# 数据模型与实现基线
|
||||
|
||||
更新:2026-09-17。当前为基础实现阶段,完整调度与编排引擎仍在开发计划中。
|
||||
更新:2026-09-17。当前已实现任务执行、安全重试与计划调度;剩余资源控制、订阅及流程编排继续开发。
|
||||
|
||||
## 1. 模块与依赖
|
||||
|
||||
@@ -113,4 +113,6 @@ P2 服务端已新增会话隔离、两步派发、租约、并发许可、结
|
||||
|
||||
000005_safe_retry 增加任务 EffectUncertain、尝试与证据 Retryable 字段,Go 与 SQL 均附中文说明;实体数仍为 32。跨尝试的不确定效果必须保留,历史 NEEDS_REVIEW 保守回填 true,旧状态、版本和冻结策略不变。回执增加 `(namespace_id, attempt_id, operation, request_digest)` 索引,换消息身份重报结果也返回原已应用回执。字段语义、升级策略启用与限制见 [安全重试](api/retries.md),升级回归见 [阶段报告](reports/phase-3-safe-retry.md)。
|
||||
|
||||
000006_schedule_runtime 增加 Schedule.QueueID / ProcessingVersion / CheckAt 以及 ScheduleVersion.CatchupWindowMS / GraceMS。字段、单位、可空语义均有中文注释;CoveredUntil 明确为合并或跳过范围的排除边界。实体数不变,增加扫描、列表和任务来源索引。时间规则 JSON 冻结 CalendarVersion,服务内置相应时区快照。调度记录、生成任务、事件和进度同事务写入,旧版本积压不会被新发布覆盖;详见 [计划契约](api/schedules.md)。
|
||||
|
||||
命令与验证记录见 [开发计划](08-development-plan.md)、[基础阶段验证报告](reports/phase-0.md) 与 [执行历史回归](reports/phase-2-execution-history.md)。
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
| P0 基础与数据模型 | Go workspace、独立 SDK module、公共/Pulse/Weave 模型、MySQL 迁移、配置、健康检查 | 编译/竞态/静态检查;真实 MySQL 建表、隔离、唯一性、预算、不可变版本、迁移失败防护;SDK 健康调用 | 已完成并通过阶段回归(见 P0 报告) |
|
||||
| P1 任务受理闭环 | 应用凭据与作用域权限、队列、幂等提交、查询、待执行取消、受理事件;SDK 客户端 | API/SDK 创建查询闭环;重复键与内容冲突、响应未确认重报、跨命名空间拒绝、参数边界 | 已完成并通过阶段回归(见 P1 报告;真实断路/提交 ACK 丢失注入留后续故障阶段) |
|
||||
| P2 Worker 执行闭环 | WSS 接入、能力/容量、领取与开始、租约、续租、结果确认、排空与恢复;Worker SDK | 真 Worker 执行;失联/重连/重复确认/旧尝试拒绝;业务效果未知转核查;节点故障接管 | 已完成并通过阶段回归:服务端、自动 SDK、历史查询、完整 Schema 与真实进程强杀恢复;测试拓扑和剩余生产故障矩阵见 P2 验收报告 |
|
||||
| P3 Pulse 完整能力 | 安全重试、延时、Cron/固定间隔、漏跑策略、计划版本、并发许可、配额/背压、可靠结果订阅 | 多实例领取/触发竞争、重试上限、取消竞争、队列隔离、积压恢复、事件重复交付 | 进行中:安全重试、退避、未知效果保留、升级回填及 SDK 场景已通过回归;Cron/固定间隔、计划管理、运行中取消、配额/背压和订阅待开发 |
|
||||
| P3 Pulse 完整能力 | 安全重试、延时、Cron/固定间隔、漏跑策略、计划版本、并发许可、配额/背压、可靠结果订阅 | 多实例领取/触发竞争、重试上限、取消竞争、队列隔离、积压恢复、事件重复交付 | 进行中:安全重试、Cron/固定间隔、版本、暂停恢复、有限漏跑/重叠策略和 SDK 场景已实现并回归;运行中取消、配额/背压和可靠订阅待开发 |
|
||||
| P4 Weave 主流程 | SDK 定义构建与发布校验、实例、顺序/分支/结构化并行汇合、信号/定时等待、版本绑定 | 重启接续、早到/重复信号、并行竞争、内部事件重放、发布版本兼容;端到端通用流程 | 待开发 |
|
||||
| P5 Weave 恢复与查询 | 有界查询、暂停继续、取消、人工核查恢复、控制门控与审计 | 轮次与尝试独立预算;暂停/开始/回执/超时竞争;恢复保留预算;未知结果不盲目重复 | 待开发 |
|
||||
| P6 生产验证与运维 | 完整监控、凭据轮换、备份恢复、滚动升级、运行手册、可复现负载和故障工具 | 对照生产验收清单执行,报告环境/指标/遗留项;容量、RPO/RTO 按真实拓扑验证 | 待开发 |
|
||||
@@ -42,7 +42,7 @@ SDK、文档与示例随 P1–P5 同步开发,P7 是全量核对,不是最
|
||||
| 健康检查 | 创建客户端 → 存活/就绪查询 | P0 |
|
||||
| 文件转换任务 | 提交幂等任务 → Worker 处理 → 查询结果 | P1–P2 |
|
||||
| 有限安全重试 | 明确失败 → 持久化退避 → 新尝试 → 查询完整历史 | P3,已实现完整示例 |
|
||||
| 定期数据同步 | 发布计划 → 触发任务 → 暂停/恢复 → 查看触发记录 | P3 |
|
||||
| 定期数据同步 | 发布计划 → 触发任务 → 暂停/恢复 → 查看触发记录 | P3,已实现通用快照示例 |
|
||||
| 并行生成结果 | 发布流程 → 并行执行 → 汇合 → 完成 | P4 |
|
||||
| 审核与外部回执 | 提交流程 → 等待信号 → 授权信号注入 → 继续 | P4 |
|
||||
| 外部作业轮询 | 提交一次 → 有界查询处理中状态 → 回执或最终结果 → 超限核查 | P5 |
|
||||
@@ -77,6 +77,7 @@ SDK、文档与示例随 P1–P5 同步开发,P7 是全量核对,不是最
|
||||
- [P1 验证记录](reports/phase-1.md)
|
||||
- [P2 阶段验收与进程故障记录](reports/phase-2.md)
|
||||
- [P3 安全重试阶段记录](reports/phase-3-safe-retry.md)
|
||||
- [P3 计划调度阶段记录](reports/phase-3-schedules.md)
|
||||
- [P2 服务端阶段记录](reports/phase-2-server.md)
|
||||
- [P2 SDK 协议阶段记录](reports/phase-2-sdk-protocol.md)
|
||||
- [P2 自动 Worker 运行器记录](reports/phase-2-worker-runtime.md)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
- 文档版本:0.2
|
||||
- 整理日期:2026-09-17
|
||||
- 阶段:P0–P2 已通过阶段验收,包括协议 Schema 与真实进程故障恢复;P3 安全重试已通过回归,P3–P7 继续推进,尚未完成全平台生产验收
|
||||
- 阶段:P0–P2 已通过阶段验收,包括协议 Schema 与真实进程故障恢复;P3 安全重试与计划调度已通过回归,P3–P7 继续推进,尚未完成全平台生产验收
|
||||
- 适用范围:Orbit 统一平台,包含 Pulse 任务调度模块、Weave 流程编排模块与公共能力。平台面向多个业务系统复用。
|
||||
|
||||
## 阅读顺序
|
||||
@@ -58,7 +58,7 @@ Orbit 不内置特定行业规则;Pulse 管理执行,Weave 管理步骤依
|
||||
| Weave 技术细则 | 功能范围已确认;SDK/定义 Schema、暂停门控与计时、查询预算、并行失败策略、人工恢复身份仍需评审 | [流程](06-workflow-spec.md) |
|
||||
| WS 库及后续依赖版本 | 当前基础使用 Go 1.27.1、MySQL 8.4+ 与显式 SQL;WS 已锁定 coder/websocket v1.8.15,后续依赖需单独验证 | [模型基线](07-data-model.md) |
|
||||
| 人工重试的任务身份 | 建议创建关联的新任务,自动重试保持原任务 ID | [功能](01-functional-spec.md) |
|
||||
| Cron、固定间隔与夏令时细节 | 建议五段 Cron、固定间隔首版采用 fixed-rate;夏令时行为需明确 | [功能](01-functional-spec.md) |
|
||||
| Cron、固定间隔与夏令时细节 | 已实现五段 Cron、fixed-rate;缺失时刻跳过、重复时刻按 UTC 分开;时区快照随版本冻结 | [计划接口](api/schedules.md) |
|
||||
| 批量大小、消息上限、心跳、租约、扫描周期 | 均需设置有限上限;数值通过原型与压测确定 | [验收](05-production-acceptance.md) |
|
||||
| 幂等、事件、审计的保留周期 | 按恢复与业务追溯要求确定,不能仅随任务清理 | [数据](04-reliability-and-data.md) |
|
||||
| 数据库高可用与恢复目标 | 明确故障模型、复制确认、RPO / RTO 及运维责任 | [验收](05-production-acceptance.md) |
|
||||
@@ -79,4 +79,4 @@ Orbit 不内置特定行业规则;Pulse 管理执行,Weave 管理步骤依
|
||||
|
||||
2026-09-17,文档更新至 0.2:用户确认研发定义发布流程及 Weave 首版功能,明确纳入有界重复查询和暂停/继续等生产管理能力。技术细则与参数继续按建议或待定标注,未将功能确认等同于实现或验收通过。
|
||||
|
||||
持续开发目标已建立。当前实现和验收进度以 [开发计划](08-development-plan.md)、[P0 报告](reports/phase-0.md)、[P1 报告](reports/phase-1.md) 与 [P2 阶段验收](reports/phase-2.md) 和 [P3 安全重试报告](reports/phase-3-safe-retry.md) 为准;早期设计稿中的“未实现”描述保留其编写阶段语境。
|
||||
持续开发目标已建立。当前实现和验收进度以 [开发计划](08-development-plan.md)、[P0 报告](reports/phase-0.md)、[P1 报告](reports/phase-1.md) 与 [P2 阶段验收](reports/phase-2.md) 、[P3 安全重试报告](reports/phase-3-safe-retry.md) 和 [P3 计划调度报告](reports/phase-3-schedules.md) 为准;早期设计稿中的“未实现”描述保留其编写阶段语境。
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
| 凭据校验与初始化 CLI | P1 已实现 | [鉴权](authentication.md) |
|
||||
| `/v1/worker/connect` | P2 已实现并通过阶段验收 | [Worker 契约](worker.md)、[Schema](worker-schema.md) |
|
||||
| 任务冻结策略与 Worker `retryable` | P3 安全重试已实现 | [安全重试](retries.md) |
|
||||
| `/v1/schedules` 与计划管理 | 计划 P3,尚未实现 | [协议草案](../03-http-websocket-protocol.md) |
|
||||
| `/v1/schedules`、不可变版本、暂停/恢复及触发查询 | P3 已实现 | [计划接口与 SDK 场景](schedules.md) |
|
||||
| `/v1/events/connect` | 计划 P3,尚未实现 | [协议草案](../03-http-websocket-protocol.md) |
|
||||
| `/v1/workflows` 与流程管理 | 计划 P4–P5,尚未实现 | [流程接口规划](workflows.md) |
|
||||
|
||||
|
||||
@@ -52,4 +52,6 @@ actions 不支持通配符;queues 可列出队列 ID,星号仅表示当前
|
||||
|
||||
SDK 使用 `orbit.Options{Token: token}`。健康查询不发送凭据。当前不启用业务权限缓存,撤销校验不依赖缓存过期。
|
||||
|
||||
P3 增加 schedules:read 和 schedules:manage。bootstrap 显式传 --schedule-access 才授予;创建/发布计划还需要 tasks:submit 与队列范围。已有计划属于命名空间,创建凭据到期或撤销不自动暂停计划;停止新触发应暂停计划,或禁用应用/命名空间。详见 [计划接口](schedules.md)。
|
||||
|
||||
P2 增加 workers:connect 和 workers:consume。bootstrap 只有显式提供 --worker-access 时才同时授予这两项开发权限;现有凭据不自动变化。Worker 还需独立的进程恢复秘密和尝试秘密,见 [Worker 契约](worker.md)。
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# 安全重试 v1
|
||||
|
||||
状态:P3 的安全重试已实现。使用现有任务提交与 Worker 结果接口,无独立的自动重试路由;Cron、运行中取消、人工恢复与可靠结果订阅继续按 [计划](../08-development-plan.md) 开发。验证证据见 [本阶段报告](../reports/phase-3-safe-retry.md)。
|
||||
状态:P3 的安全重试已实现。使用现有任务提交与 Worker 结果接口,无独立的自动重试路由;[Cron/固定间隔计划](schedules.md) 已接入;运行中取消、人工恢复与可靠结果订阅继续按 [计划](../08-development-plan.md) 开发。验证证据见 [本阶段报告](../reports/phase-3-safe-retry.md)。
|
||||
|
||||
## 1. 三种不同的重报
|
||||
|
||||
|
||||
219
docs/api/schedules.md
Normal file
219
docs/api/schedules.md
Normal file
@@ -0,0 +1,219 @@
|
||||
# 调度计划接口 v1
|
||||
|
||||
状态:已实现五段 Cron、fixed-rate、不可变版本、暂停/恢复、三种漏跑与重叠策略、触发历史及独立 SDK。调度记录、任务创建、事件与进度同事务提交。当前实际验证与边界见 [阶段报告](../reports/phase-3-schedules.md),整体仍按 [开发计划](../08-development-plan.md) 推进。
|
||||
|
||||
## 1. 权限与生命周期
|
||||
|
||||
| 接口 | 权限 | SDK |
|
||||
| --- | --- | --- |
|
||||
| POST /v1/schedules | schedules:manage + tasks:submit + 模板队列范围 | CreateSchedule |
|
||||
| GET /v1/schedules?queue_id=… | schedules:read + 队列范围 | ListSchedules |
|
||||
| GET /v1/schedules/{id} | schedules:read + 计划队列范围 | GetSchedule |
|
||||
| PATCH /v1/schedules/{id} | schedules:manage + tasks:submit + 计划队列范围 | PublishSchedule |
|
||||
| POST /v1/schedules/{id}:pause | schedules:manage + 计划队列范围 | PauseSchedule |
|
||||
| POST /v1/schedules/{id}:resume | schedules:manage + 计划队列范围 | ResumeSchedule |
|
||||
| GET /v1/schedules/{id}/versions/{version} | schedules:read + 计划队列范围 | GetScheduleVersion |
|
||||
| GET /v1/schedules/{id}/occurrences | schedules:read + 计划队列范围 | ListScheduleOccurrences |
|
||||
|
||||
计划终身绑定一个队列。发布完整新定义时可以改变时间、参数和策略,不能更换队列。计划属于命名空间;创建凭据后续到期/撤销不自动撤销已创建的计划。停止计划使用暂停接口,禁用应用或命名空间会阻止后台继续创建任务。每次管理与查询仍重新校验当前凭据。
|
||||
|
||||
计划暂停只停止产生新的任务,已经受理的任务继续执行。队列暂停只停止任务派发,不停止计划受理,可能形成积压。SERIAL 策略将 WAITING、LEASED、RUNNING、NEEDS_REVIEW 都视为未完成;未知效果未处理时不能开始下一轮。
|
||||
|
||||
请求使用 Bearer、application/json 和稳定的 Idempotency-Key,沿用 [任务接口](tasks.md) 的 512 KiB 请求、严格 JSON、命名空间隔离和精确数字规则。ID 为 32 位小写十六进制,revision/version 为十进制字符串,时间为 UTC RFC 3339 微秒精度。
|
||||
|
||||
## 2. 创建与定义字段
|
||||
|
||||
CreateScheduleRequest:name、definition 必填;paused 默认 false。name 为命名空间内唯一的 1–128 位 ASCII 名称,字符规则同任务处理器。definition 包含 rule、policy、task,三者均需明确提供。
|
||||
|
||||
| rule 字段 | 含义与边界 |
|
||||
| --- | --- |
|
||||
| kind | CRON 或 FIXED_RATE |
|
||||
| timezone | 必填 IANA 名称,如 UTC、Asia/Shanghai;不接受 Local 或文件路径 |
|
||||
| calendar_version | 可省略,v1 固定默认 `go1.27.1-b2d18a7c8fa8`;规范化后写入版本快照,其他未支持值拒绝 |
|
||||
| start_at | 必填基准,包含边界;年份 2000–9998,最多微秒 |
|
||||
| end_at | 可选排除边界,必须晚于 start_at;达到后不再产生新触发点 |
|
||||
| cron | CRON 必填五段表达式,最多 256 字符;不接受秒段、@every 等描述符或内嵌 TZ= |
|
||||
| interval_ms | FIXED_RATE 必填,1000–2592000000 毫秒;此时不能设置 cron |
|
||||
|
||||
新计划的第一个点不早于数据库创建时刻;start_at 在过去时只用作规则基准,不追溯生成计划存在前的任务。创建时必须还有未来触发点。新发布版本可以设置已经结束的规则,此时先处理旧积压,再结束后续调度。
|
||||
|
||||
Cron 段顺序为分钟、小时、月日、月、星期;支持 `*`、列表、范围、步长、月份/星期名称,星期为 0–6(周日为 0)。月日与星期均受限时按 OR 匹配,有通配段时按标准组合规则匹配。采用 [robfig/cron v3.0.1 的解析器](https://github.com/robfig/cron/tree/v3.0.1),Orbit 自行按时区偏移区间转换 UTC 触发点,不启动该库的内存调度器。
|
||||
|
||||
时区快照内置于服务二进制,不读取宿主机时区文件或 ZONEINFO。快照来自 Go 1.27.1 的 zoneinfo.zip,完整 SHA-256 为 `b2d18a7c8fa8142097a48c99609fb3c92db5ee98bc740294e57eab8ae9f94779`。升级时必须保留旧快照可读能力和 v1 默认语义,不能把旧计划静默换成新的时区规则。
|
||||
|
||||
- 夏令时缺失的本地时刻跳过;重复的本地时刻按两个不同 UTC 时间分别触发。
|
||||
- 半小时跳变、整天跳过、非整点时区和世纪闰日都有测试。
|
||||
- fixed-rate 始终按 `start_at + n × interval_ms` 的实际经过时间计算,不跟随上一任务的完成时间漂移。
|
||||
- 无解日期规则、混合字段和无效时区在发布前拒绝。无后续触发点与计算错误分开处理,错误不能静默当作完成。
|
||||
|
||||
| policy 字段 | 要求 |
|
||||
| --- | --- |
|
||||
| misfire | 必填:SKIP、COALESCE、CATCH_UP |
|
||||
| overlap | 必填:PARALLEL、SERIAL、SKIP |
|
||||
| catchup_limit | 必填 1–100,每批最多生成任务数;大参数批次还受约 1 MiB 参数复制量限制 |
|
||||
| catchup_window_ms | 必填 1000–2592000000,未处理触发点最多保留的时间窗口 |
|
||||
| grace_ms | 必填 1000–60000,正常派发允许延迟;不能超过 catchup_window_ms |
|
||||
|
||||
所有任务策略在 task 内冻结,字段同 SubmitTaskRequest;payload 最大 256 KiB,数字文本保持精确。task 中禁止绝对 available_at / start_deadline_at,每次生成时立即可受理,task_timeout_ms 从本次实际创建时间计算。计划结束不取消已经生成的任务,也不缩短其任务时限。
|
||||
|
||||
创建请求示例,ID 和未来时间替换为实际值:
|
||||
|
||||
```json
|
||||
{
|
||||
"name":"object-snapshot",
|
||||
"paused":true,
|
||||
"definition":{
|
||||
"rule":{"kind":"FIXED_RATE","timezone":"UTC","start_at":"2026-10-01T00:00:00Z","interval_ms":60000},
|
||||
"policy":{"misfire":"COALESCE","overlap":"SERIAL","catchup_limit":10,"catchup_window_ms":86400000,"grace_ms":5000},
|
||||
"task":{"queue_id":"11111111111111111111111111111111","handler":"object.snapshot","handler_version":"v1","payload_version":"v1","payload":{"source_ref":"objects/sample","sequence":9007199254740993},"task_timeout_ms":30000,"retry":{"max_attempts":1,"attempt_timeout_ms":5000}}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```sh
|
||||
curl "$ORBIT_URL/v1/schedules" \
|
||||
-H "Authorization: Bearer $ORBIT_TOKEN" \
|
||||
-H 'Content-Type: application/json' -H 'Idempotency-Key: snapshot-plan-001' \
|
||||
--data-binary @schedule.json
|
||||
```
|
||||
|
||||
将上方 JSON 保存为 schedule.json。首次返回 201,同键同内容返回 200;均不表示已有任务完成。响应示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"request_id":"44444444444444444444444444444444",
|
||||
"data":{
|
||||
"deduplicated":false,
|
||||
"schedule":{
|
||||
"id":"22222222222222222222222222222222","namespace_id":"33333333333333333333333333333333",
|
||||
"queue_id":"11111111111111111111111111111111","name":"object-snapshot",
|
||||
"revision":"1","current_version":"1","processing_version":"1","paused":true,
|
||||
"next_fire_at":"2026-10-01T00:00:00Z","check_at":"2026-10-01T00:00:00Z",
|
||||
"created_at":"2026-09-17T08:00:00Z","updated_at":"2026-09-17T08:00:00Z",
|
||||
"current":{
|
||||
"version":"1","effective_at":"2026-09-17T08:00:00Z",
|
||||
"definition":{
|
||||
"rule":{"calendar_version":"go1.27.1-b2d18a7c8fa8","kind":"FIXED_RATE","timezone":"UTC","start_at":"2026-10-01T00:00:00Z","interval_ms":60000},
|
||||
"policy":{"misfire":"COALESCE","overlap":"SERIAL","catchup_limit":10,"catchup_window_ms":86400000,"grace_ms":5000},
|
||||
"task":{"queue_id":"11111111111111111111111111111111","handler":"object.snapshot","handler_version":"v1","payload_version":"v1","payload":{"source_ref":"objects/sample","sequence":9007199254740993},"task_timeout_ms":30000,"recovery_safety":"RECONCILE_ONLY","retry":{"max_attempts":1,"initial_delay_ms":0,"max_delay_ms":0,"attempt_timeout_ms":5000}}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
GetSchedule 的 data 直接为 schedule 对象。列表 Items 省略 current/大参数,其他字段相同。next_fire_at 是下一原计划时间,积压时可能在过去;check_at 是平台下次允许扫描时间,并不保证届时执行。next_fire_at 为空时,可能尚待初始化某个版本的首个触发点,也可能已经结束;即使 processing_version 等于 current_version,也必须结合 check_at 判断。check_at 非空表示仍有扫描工作,为空且处理到最新版本表示已无后续触发。
|
||||
|
||||
## 3. 漏跑、重叠与有限补偿
|
||||
|
||||
先处理超过 catchup_window_ms 的范围并记录 CATCHUP_WINDOW_EXCEEDED,再应用漏跑规则:
|
||||
|
||||
| 策略 | 行为 |
|
||||
| --- | --- |
|
||||
| SKIP | 早于 now − grace_ms 的点合为跳过范围;容差内的点仍可受理 |
|
||||
| COALESCE | 若最早积压点超过 grace_ms,将当前版本内本轮所有已到期点合为一个任务 |
|
||||
| CATCH_UP | 按原时间逐点创建,单批不超过 catchup_limit,剩余进度保留到下一批 |
|
||||
| PARALLEL | 可以产生多条未完成任务,实际执行仍受队列与 Worker 并发许可限制 |
|
||||
| SERIAL | 有任一先前计划任务未终结时保留游标等待;没有未完成任务时本批最多创建一条 |
|
||||
| SKIP 重叠策略 | 有先前未终结任务时跳过本轮已到期范围;否则本批最多创建一条 |
|
||||
|
||||
SERIAL 等待也受时间窗口约束,过旧范围会被记录为跳过,避免无界补偿。NEEDS_REVIEW 不属于明确终态,会持续阻止串行后续任务;取消或失败不能假装外部效果已消失。
|
||||
|
||||
每节点每秒扫描最多 100 个候选计划,每个计划单独事务。同一计划相邻批次的数据库决策时间至少间隔一秒,check_at 持久化,多节点不会各自补跑一份。每批最多创建一个历史版本的任务,跨版本也不绕过批量上限;空版本每批最多推进 16 个。当前是有界运行基线,不是已验证的生产吞吐承诺。
|
||||
|
||||
每个触发身份由命名空间、计划 ID、原 UTC scheduled_at 唯一确定。暂停、重连和发布新版本都不会改变旧身份。跳过/合并记录的覆盖区间为 `[scheduled_at, covered_until)`,结束边界不包含;范围不会跨越版本生效时间,也不会为范围内每个点额外创建任务。
|
||||
|
||||
## 4. 发布、暂停与恢复
|
||||
|
||||
PATCH 是完整发布,必须包含 expected_revision(非零十进制字符串)、reason(非空,最多 1024 字符)、definition(完整新定义)。发布后 current_version 增加一,新版本以事务读取的数据库时间立即生效。
|
||||
|
||||
尚未处理且早于新版本生效边界的点仍按旧规则、旧模板和旧策略决定。后续原时间由新版本计算,已生成任务保持原快照。数据库触发器禁止覆盖已发布版本。GET versions/{version} 返回 version、effective_at、definition;version 必须是无前导零的非零十进制数。
|
||||
|
||||
暂停/恢复请求体相同:
|
||||
|
||||
```json
|
||||
{"expected_revision":"1","reason":"start regular snapshots"}
|
||||
```
|
||||
|
||||
成功返回 200,data 与创建回执结构相同。暂停不清空游标,恢复按冻结漏跑规则处理暂停期间的点。对已经处于目标暂停状态的计划换键操作返回 STATE_CONFLICT;原键原内容重报仍返回原回执。
|
||||
|
||||
- 管理操作、不可变版本、事件、审计和幂等回执同事务保存。后台触发持久化 occurrence、task.accepted、schedule.decided、schedule.advanced,记录执行节点。
|
||||
- 每次扫描也更新 revision。遇到明确 STATE_CONFLICT,先 GET 新状态,再用新的命令身份和新 expected_revision 操作;网络结果不明时必须复用原键和原版本核对。
|
||||
- 同键更改定义、reason 或 expected_revision 返回 IDEMPOTENCY_CONFLICT。原回执不表示计划当前仍是该状态。
|
||||
- 计划名称不能修改,暂无删除或单次手动触发接口。WAITING 的已生成计划任务可用任务取消接口取消,计划本身继续运行;流程归属任务仍由后续流程控制管理。
|
||||
|
||||
## 5. 列表与触发记录
|
||||
|
||||
ListSchedules 需要 queue_id;计划列表和 occurrences 均可用 limit(默认 20,1–100)、cursor(最多 1024 字符)。未知、重复查询参数或错误游标返回 400。详情接口不接受查询参数。
|
||||
|
||||
计划按 `(created_at DESC,id DESC)`,触发按 `(scheduled_at DESC,id DESC)` 分页,不使用 offset。游标绑定命名空间、队列或计划及查询类型。读取不承诺跨页快照;空列表为 items: [],有下一页才返回 next_cursor。
|
||||
|
||||
```json
|
||||
{
|
||||
"request_id":"44444444444444444444444444444444",
|
||||
"data":{"items":[{
|
||||
"id":"55555555555555555555555555555555","schedule_id":"22222222222222222222222222222222",
|
||||
"schedule_version":"1","scheduled_at":"2026-10-01T00:00:00Z","decision":"COALESCED",
|
||||
"task_id":"66666666666666666666666666666666","covered_until":"2026-10-01T00:03:00.000001Z",
|
||||
"reason":"MISFIRE_COALESCED","created_at":"2026-10-01T00:03:00Z"
|
||||
}]}
|
||||
}
|
||||
```
|
||||
|
||||
FIRED 表示已创建单点任务;COALESCED 表示范围已合并到 task_id;SKIPPED 没有 task_id。它们都不是业务执行结果,继续 GetTask 查询,再通过 [尝试与证据接口](execution-history.md) 核对执行。
|
||||
|
||||
## 6. SDK 与完整示例
|
||||
|
||||
所有方法首参数为 context.Context,写操作需要稳定 key。ListSchedules 的参数为 `(ctx, queueID, SchedulePageRequest)`;ListScheduleOccurrences 为 `(ctx, scheduleID, SchedulePageRequest)`。
|
||||
|
||||
在已有服务和当前迁移基础上,创建专用开发凭据:
|
||||
|
||||
```sh
|
||||
go run ./cmd/orbit-admin bootstrap \
|
||||
--application schedule-demo --namespace default --environment development \
|
||||
--queue snapshots --worker-access --schedule-access \
|
||||
--output .local/schedule.credentials.json
|
||||
cd sdk/go
|
||||
ORBIT_URL=http://127.0.0.1:8080 \
|
||||
ORBIT_CREDENTIALS_FILE=../../.local/schedule.credentials.json \
|
||||
go run ./examples/schedules
|
||||
```
|
||||
|
||||
前置数据库与目录步骤见 [SDK 接入](../sdk/README.md)。源码:[完整调度示例](../../sdk/go/examples/schedules/main.go)。示例创建暂停的每秒计划,恢复后让自动 Worker 返回对象输入快照,查询两次完成,再暂停并排空。计划本身有十秒结束边界,任务与历史保留;重复运行生成独立身份,不调用外部业务系统。
|
||||
|
||||
```text
|
||||
schedule=<计划ID> occurrence=<触发ID> task=<任务ID> version=1 state=SUCCEEDED
|
||||
schedule=<计划ID> occurrence=<触发ID> task=<任务ID> version=1 state=SUCCEEDED
|
||||
paused=true completed_tasks=2 current_version=1
|
||||
worker_drained=true running=0
|
||||
```
|
||||
|
||||
调度或查询有延迟时可能观察到更多已产生的任务。异常时非零退出,Worker 尝试有界收尾;暂停不回滚已产生任务。接入函数可直接用以下片段发布 Cron 版本:
|
||||
|
||||
```go
|
||||
current, err := client.GetSchedule(ctx, scheduleID)
|
||||
if err != nil { return err }
|
||||
definition := current.Current.Definition
|
||||
definition.Rule.Kind = "CRON"
|
||||
definition.Rule.Cron = "0 9 * * MON-FRI"
|
||||
definition.Rule.IntervalMS = 0
|
||||
definition.Rule.Timezone = "Asia/Shanghai"
|
||||
updated, err := client.PublishSchedule(ctx, scheduleID, operationKey, orbit.PublishScheduleRequest{
|
||||
ExpectedRevision: current.Revision,
|
||||
Reason: "use weekday snapshot cadence",
|
||||
Definition: definition,
|
||||
})
|
||||
if err != nil { return err }
|
||||
fmt.Println(updated.Schedule.CurrentVersion)
|
||||
```
|
||||
|
||||
保留原 calendar_version,并核对 start_at/end_at 是否仍覆盖期望时间。发布时不会取消旧版本已创建任务。
|
||||
|
||||
## 7. 错误与升级
|
||||
|
||||
错误信封同 [任务接口](tasks.md)。400 表示字段、时间、时区快照、游标或队列变更非法;401 表示凭据/应用/命名空间不可用;403 表示缺少动作或列表/创建队列范围;404 隐藏不存在或单资源越权;409 表示名称、状态、版本或幂等内容冲突;503 时写操作可能已经提交,应保留原身份核对。
|
||||
|
||||
迁移 000006 增加绑定队列、历史处理版本、扫描时间、窗口与容差,以及调度/任务来源索引。此前只有结构、没有创建计划接口;原人工行的 queue_id/check_at 为 NULL,不自动启用。迁移不会猜测任务模板对应的授权队列;此类行需由管理员核查后通过正式接口建立受控计划。
|
||||
|
||||
服务仍只依赖 MySQL,不需要外部 Cron、消息队列或协调服务。生产跨主机、数据库切换、在线迁移、海量积压与公平性测试尚待 P6;当前计划能力不代表完整生产验收已通过。
|
||||
@@ -54,12 +54,21 @@
|
||||
- 异常:次数/时限耗尽停止重试;未知效果默认转核查。`Retryable=true` 需要明确的安全依据,不能用于普通网络超时。
|
||||
- 清理:示例不调用外部业务系统,每次创建独立任务并保留历史;失败时非零退出并有界收尾。
|
||||
|
||||
## 已可运行:周期对象快照
|
||||
|
||||
- 源码:[调度示例](../../sdk/go/examples/schedules/main.go),[初始化、调用与输出](../api/schedules.md#6-sdk-与完整示例)。
|
||||
- 前置:当前迁移、服务,显式 --schedule-access 与 --worker-access 的专用开发凭据。
|
||||
- 步骤:创建暂停的有限每秒计划 → 恢复 → 自动 Worker 返回输入快照 → 查到至少两次任务成功 → 暂停并排空。
|
||||
- 预期:不同 occurrence/task 身份、相同计划版本、paused=true、running=0;精确整数保留。
|
||||
- 异常:串行前项未知时不新建后续任务;恢复按版本与漏跑策略处理,超过窗口记录跳过。暂停不撤销已生成任务。
|
||||
- 清理:计划最终暂停,自带十秒结束边界;失败非零退出,历史保留,无外部业务副作用。
|
||||
|
||||
## 计划场景与验收标准
|
||||
|
||||
| 场景 | 输入与步骤 | 预期结果 | 必测异常 | 状态 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 文件转换 | 对象引用 → 提交任务 → Worker 转换 → 结果引用 | 同一操作获得一次业务结果,历史可查 | 重复提交、Worker 在结果上报前中断 | 受理与执行框架已实现,实际转换示例待补齐 |
|
||||
| 定期同步 | 发布计划 → 周期触发 → 暂停 → 恢复 | 触发身份唯一,漏跑策略可追溯 | 多节点竞争、停机后补跑上限 | P3 待开发 |
|
||||
| 定期同步 | 发布计划 → 周期触发 → 暂停 → 恢复 | 触发身份唯一,漏跑策略可追溯 | 多节点竞争、停机后补跑上限 | P3 通用快照示例已完成,业务同步由接入方处理器实现 |
|
||||
| 并行生成 | 输入对象 → 并行计算两份结果 → 汇合 | 两支满足条件后只创建一份后继工作 | 一支失败、重复结果、汇合竞争 | P4 待开发 |
|
||||
| 等待审核 | 校验 → 等待信号 → 发布结果 | 只接受授权、匹配当前操作的信号 | 早到、重复、过期与越权信号 | P4 待开发 |
|
||||
| 外部作业查询 | 提交一次 → 间隔查询 → 最终结果 | 处理中消耗轮次,请求失败消耗尝试 | 回执与查询竞争、预算耗尽、响应未知 | P5 待开发 |
|
||||
|
||||
96
docs/reports/phase-3-schedules.md
Normal file
96
docs/reports/phase-3-schedules.md
Normal file
@@ -0,0 +1,96 @@
|
||||
# P3 计划调度阶段记录
|
||||
|
||||
验证日期:2026-09-17。已交付计划管理与持久化调度闭环,P3 仍有运行中取消、配额/背压、可靠订阅待完成;本报告不替代全平台生产验收。
|
||||
|
||||
## 1. 已实现行为
|
||||
|
||||
- 五段 Cron 与 fixed-rate;显式时区、开始和结束边界,固定间隔保持基准,不按任务完成时间漂移。
|
||||
- 时区快照随定义冻结,服务从内置数据加载,不依赖宿主机或 ZONEINFO;兼容已有快照是后续升级约束。
|
||||
- 创建、队列分页、详情、完整版本发布、历史版本、暂停/恢复、触发历史。每个命令有当前权限校验、幂等回执与管理审计。
|
||||
- SKIP / COALESCE / CATCH_UP 漏跑策略与 PARALLEL / SERIAL / SKIP 重叠策略;明确补偿窗口、延迟容差、批量和扫描间隔。
|
||||
- 发布新版本保留旧生效边界前的积压;跳过和合并范围不越过版本边界。已产生任务保留当时模板。
|
||||
- 多节点用数据库锁与唯一触发身份竞争;触发决定、对应任务、事件及进度一起提交。
|
||||
- 实际 orbit 命令持续扫描,独立 SDK 与 [完整周期快照示例](../../sdk/go/examples/schedules/main.go) 同步交付。
|
||||
- 迁移 000006 增加运行字段与索引,实体仍为 32 个;新模型字段及 SQL COMMENT 均为中文;源码核对 32 个持久化模型、253 个直接声明的持久化字段均有中文说明。
|
||||
|
||||
完整字段、权限、状态与示例见 [接口手册](../api/schedules.md)。
|
||||
|
||||
## 2. 环境、命令及结果
|
||||
|
||||
macOS 本机,Go 1.27.1,Docker 单实例 MySQL 8.4.10。临时随机凭据、回环随机端口,运行结束清理容器;不使用业务数据库。
|
||||
|
||||
```sh
|
||||
make fmt
|
||||
make test vet build
|
||||
make integration
|
||||
cd sdk/go
|
||||
GOWORK=off go test -race ./...
|
||||
GOWORK=off go vet ./...
|
||||
```
|
||||
|
||||
上述检查均已通过。未配置集成环境时,普通 go test 会跳过真实数据库/进程用例;实际证据来自 make integration。
|
||||
|
||||
最终完整集成输出:
|
||||
|
||||
| 测试组 | 本次结果 |
|
||||
| --- | --- |
|
||||
| MySQL 全部集成 | PASS,44.712 秒 |
|
||||
| 计划事务与管理子集 | PASS,31.62 秒 |
|
||||
| SDK Worker 连接/运行器及安全重试 | PASS,62.912 秒 |
|
||||
| SDK 计划生命周期 | PASS,4.43 秒,含包启动/竞态开销 5.675 秒 |
|
||||
| 真实进程故障组 | PASS,21.487 秒 |
|
||||
| 新增调度进程强杀恢复 | PASS,10.23 秒 |
|
||||
| 七个可运行示例 | health / tasks / worker-protocol / worker / history / retry / schedules 全部通过 |
|
||||
|
||||
时间为一次测试运行耗时,不能用作吞吐、延迟或容量指标。
|
||||
|
||||
## 3. 时钟与规则证据
|
||||
|
||||
[规则测试](../../pulse/schedule/rule_test.go) 验证:五段/分钟边界、亚洲时区、纽约缺失/重复小时、Lord Howe 半小时夏令时变更、Apia 整天跳过、2096→2104 世纪闰日、月日/星期 OR、固定间隔微秒和跨 292 年计算、结束排除边界、规则副本隔离及无解日期拒绝。
|
||||
|
||||
[时区测试](../../internal/timezone/zone_test.go) 核对内置快照完整 SHA-256、禁用外部 ZONEINFO 后仍能加载、精确名称及缓存,以及未知快照拒绝。快照来自 Go 1.27.1,附 Go 许可。Cron 库版本固定为 v3.0.1,只用于解析和 UTC 日历计算,运行不依赖外部调度服务;SDK 未新增该依赖。
|
||||
|
||||
[有限决策测试](../../pulse/schedule/planner_test.go) 覆盖补偿窗口截断、跳过、合并、有限逐点补跑、串行阻塞、重叠跳过、未来点不处理,以及合并不越过版本生效边界。计算器不自行读取系统当前时间,执行使用资源锁定后的数据库时间。
|
||||
|
||||
## 4. 实际数据库与 SDK 证据
|
||||
|
||||
[数据库用例](../../internal/storage/mysql/schedule_integration_test.go):
|
||||
|
||||
- 两个不同节点身份并发扫描同一到期计划,只创建本批三个唯一任务;再次扫描不能绕过持久化冷却时间。
|
||||
- 禁用命名空间后,即使计划已到期也不再产生任务。
|
||||
- 创建原键重报、同键不同内容冲突、暂停禁止触发、恢复原回执、跨命名空间/队列范围拒绝。
|
||||
- 暂停期间发布新模板,旧积压仍用旧版本;历史版本不可被新模板覆盖,旧点处理后游标推进到新版本。
|
||||
- 连续发布三个有限版本:第二版本尚待初始化时再次发布,仍保存其积压;空历史版本之后的末版全部处理完时,不重新扫描已完成触发点。新增用例先复现了漏掉中间版本和重复写入冲突,再验证修复。
|
||||
- 超过时间窗口的跳过范围、漏跑合并范围与任务关联实际落库,范围结束边界大于起点。
|
||||
- SERIAL 在待执行任务存在时等待;明确取消前项后继续;前项进入 UNKNOWN / NEEDS_REVIEW 后再次停止推进。
|
||||
- 通过测试触发器让 occurrence 写入失败,任务、触发记录及游标整体回滚;故障解除后正常提交。
|
||||
- 触发游标分页无重复,不能跨计划复用游标;任务模板中的大整数文本保留。
|
||||
|
||||
上述用例以真实时间等待形成积压,不把原触发时间改到计划创建前。少量用例将受控行 check_at 设为当前时间,以加速核对连续历史版本或阻塞状态;冷却限制另有未改写 check_at 的竞争测试。
|
||||
|
||||
[SDK 用例](../../sdk/go/schedule_integration_test.go) 连接实际服务,通过独立 SDK 创建暂停计划、幂等核对、恢复、自动 Worker 成功、暂停、发布 Cron 新版本、读取两个版本、原发布回执重报、列表及暂停期间不新增触发。业务结果中的 `9007199254740993` 保持精确。
|
||||
|
||||
## 5. 实际进程强杀恢复
|
||||
|
||||
新增 [TestIntegrationWorkerProcessScheduleRecovery](../../sdk/go/worker_process_integration_test.go) 使用构建后的 orbit 可执行文件和临时 MySQL:
|
||||
|
||||
1. 节点 A 创建一个每秒触发、共八个原触发点的有限计划,CATCH_UP / PARALLEL,每批上限二。
|
||||
2. 观察到首个触发已经落库后,向 A 发送真实强杀并 Wait 确认退出。
|
||||
3. 保留三秒无 Orbit 服务的间隙形成漏跑,不修改数据库时钟或计划游标。
|
||||
4. 启动身份不同的 B、C 两个真实服务进程,从持久化进度竞争接续。
|
||||
5. 查询至计划结束,严格核对恰好八条 FIRED、八个不同 TaskID、原 scheduled_at 序列及相同版本;每条都有完整 WAITING 任务与原模板。
|
||||
|
||||
这证明了本地单 MySQL 下服务进程消失后的持久化接续与多进程触发去重。本用例不启动业务 Worker,不宣称验证外部副作用 exactly-once。原开始/完成 ACK 丢失后强杀接管、Worker 进程中断转核查等 P2 用例也同步通过。
|
||||
|
||||
## 6. 可运行场景与当前边界
|
||||
|
||||
周期快照示例输出两条不同的 occurrence/task 身份,均完成 SUCCEEDED,随后 `paused=true completed_tasks=2 current_version=1`、`worker_drained=true running=0`。示例不访问外部业务资源;计划有十秒结束边界,正常完成后暂停,历史保留。
|
||||
|
||||
仍需后续验证或开发:
|
||||
|
||||
- 运行中任务取消、细粒度限流与队列配额、可靠结果订阅;流程引擎及人工核查控制。
|
||||
- 调度期间数据库故障切换、提交 ACK 丢失的专门故障矩阵、跨主机网络分区、备份恢复和混合版本升级。
|
||||
- 大表在线 DDL、历史人工计划行核查;000006 不自动启用旧的未绑定队列行。新建数据库与既有 v4 数据升级到当前结构的通用测试通过,但这不是旧人工计划内容的完整迁移验收。
|
||||
- 大规模公平性、行锁竞争、重试/补跑风暴、历史保留与清理、租户配额。当前批量、扫描间隔和参数复制限制只建立有界基线,没有百万租户容量结论。
|
||||
|
||||
后续继续 [持续计划](../08-development-plan.md),不将本阶段闭环标为整个 P3 或最终目标完成。
|
||||
@@ -1,6 +1,6 @@
|
||||
# Go SDK 接入说明
|
||||
|
||||
已实现健康查询、任务提交/查询/分页/待执行取消、队列创建/查询、[自动 Worker](worker-runtime.md)、[Worker 底层协议 SDK](worker.md) 和 [执行历史查询](../api/execution-history.md)。[安全重试](../api/retries.md) 已提供有限策略、WorkerFailure.Retryable、历史查询及完整例子。流程构建等后续接口按 [开发计划](../08-development-plan.md) 继续实现。
|
||||
已实现健康查询、任务提交/查询/分页/待执行取消、队列创建/查询、[自动 Worker](worker-runtime.md)、[Worker 底层协议 SDK](worker.md) 和 [执行历史查询](../api/execution-history.md)。[安全重试](../api/retries.md) 已提供有限策略、WorkerFailure.Retryable、历史查询及完整例子。[计划调度](../api/schedules.md) 已支持创建、查询、版本发布、暂停/恢复、触发历史与完整示例。流程构建等后续接口按 [开发计划](../08-development-plan.md) 继续实现。
|
||||
|
||||
module:`git.yuntuo.hk/k2safe/orbit/sdk/go`。SDK 使用独立 go.mod,依赖 Go 标准库与 `github.com/coder/websocket v1.8.15`,不引用服务端模型或数据库实现。
|
||||
|
||||
@@ -105,6 +105,9 @@ fmt.Println(cancelled.Task.State)
|
||||
|
||||
| 方法 | 请求 / 返回 | 文档 |
|
||||
| --- | --- | --- |
|
||||
| CreateSchedule / GetSchedule / ListSchedules | 计划受理、详情与队列分页 | [计划](../api/schedules.md) |
|
||||
| PublishSchedule / GetScheduleVersion | 不可变发布与历史版本 | [计划](../api/schedules.md) |
|
||||
| PauseSchedule / ResumeSchedule / ListScheduleOccurrences | 控制与触发记录 | [计划](../api/schedules.md) |
|
||||
| Liveness / Readiness | Health | [健康](../api/health.md) |
|
||||
| SubmitTask | SubmitTaskRequest / SubmitTaskResult | [任务](../api/tasks.md) |
|
||||
| GetTask | taskID / Task | [任务](../api/tasks.md) |
|
||||
@@ -117,7 +120,7 @@ fmt.Println(cancelled.Task.State)
|
||||
| ListAttemptEvidence | taskID、attemptID、HistoryPageRequest / AttemptEvidencePage | [执行历史](../api/execution-history.md) |
|
||||
| GetAttemptEvidence | taskID、attemptID、evidenceID / AttemptEvidence | [执行历史](../api/execution-history.md) |
|
||||
|
||||
所有方法第一个参数为 context.Context,返回值之外都返回 error。命令方法要求调用方提供稳定 key,不自动生成或重试。ListTasksRequest 接受 QueueID、State、Limit、Cursor。
|
||||
所有方法第一个参数为 context.Context,返回值之外都返回 error。计划方法的具体参数见对应手册。命令方法要求调用方提供稳定 key,不自动生成或重试。ListTasksRequest 接受 QueueID、State、Limit、Cursor。
|
||||
|
||||
Options.HTTPClient 可注入专用 HTTP 客户端。SDK 复制配置,不修改调用方实例;默认超时 10 秒,可用 context 缩短。禁止自动跟随重定向,避免凭据被转交其他地址。生产配置 HTTPS;SDK 不承担部署 TLS 终止。
|
||||
|
||||
@@ -176,4 +179,4 @@ task=<任务ID> state=SUCCEEDED attempts=1 evidence=1 reason=RESULT_CONFLICT dis
|
||||
|
||||
## 7. 后续交付
|
||||
|
||||
P2 已提供底层协议、[自动 Worker 运行器及示例](worker-runtime.md) 与历史查询,并通过 [Schema 及进程故障阶段验收](../reports/phase-2.md);P3 已实现 [安全重试与示例](../api/retries.md),计划和结果订阅继续开发;P4–P5 提供流程构建发布、信号、等待、轮询与人工恢复。每项随实现同步交付可运行示例及异常回归。
|
||||
P2 已提供底层协议、[自动 Worker 运行器及示例](worker-runtime.md) 与历史查询,并通过 [Schema 及进程故障阶段验收](../reports/phase-2.md);P3 已实现 [安全重试与示例](../api/retries.md) 和 [计划调度与示例](../api/schedules.md),运行中取消、资源配额和结果订阅继续开发;P4–P5 提供流程构建发布、信号、等待、轮询与人工恢复。每项随实现同步交付可运行示例及异常回归。
|
||||
|
||||
Reference in New Issue
Block a user