feat: add durable safe retries with uncertainty tracking and SDK examples
This commit is contained in:
@@ -65,7 +65,7 @@ SDK 的 Run 每个实例只能调用一次,包括已经正常退出的实例
|
||||
| ReconnectMinDelay | 200 毫秒;至少 10 毫秒 | 连接失败退避起点 |
|
||||
| ReconnectMaxDelay | 5 秒;不小于起点,最多 30 秒 | 指数退避上限,区间抖动;不增加任务尝试次数 |
|
||||
|
||||
`Run(ctx)` 正常排空返回 nil;同实例再次运行返回 ErrWorkerAlreadyRun。`Stats()` 返回进程内 Running、Started、RenewalsConfirmed、ReportsConfirmed、EvidenceConfirmed、Reconnects、DroppedEvents 快照,不是持久化业务成功率。
|
||||
`Run(ctx)` 正常排空返回 nil;同实例再次运行返回 ErrWorkerAlreadyRun。`Stats()` 返回进程内 Running、Started、RenewalsConfirmed、ReportsConfirmed、EvidenceConfirmed、Reconnects、DroppedEvents 快照,不是持久化业务成功率。ReportsConfirmed 包含已确认的失败/未知尝试报告,一条重试任务可能计多次。
|
||||
|
||||
`Events()` 是 128 条缓冲的只读本地通知流,不读取也不会阻塞运行;缓冲满时丢弃并计数,Run 返回时关闭。通知只含类型、任务/尝试 ID 与稳定分类,没有业务结果或秘密。它不能代替审计、可靠结果订阅或任务查询。
|
||||
|
||||
@@ -78,15 +78,16 @@ SDK 的 Run 每个实例只能调用一次,包括已经正常退出的实例
|
||||
- 重连复用实例和尝试身份,在开启容量之前 Resume 所有已知尝试;待确认 start/renew/finish 使用原消息 ID。认证、权限及协议错误终止 Run;临时服务/连接错误按退避核对。
|
||||
- 结果未确认或处理器失去租约时,运行器降低对外声明的容量。仍未返回的函数占用真实并发槽;已在传输中的预占会有界接收,已知尝试最多为配置容量的两倍。
|
||||
|
||||
Run 的重连是控制消息恢复,不是业务自动重试。当前明确失败仍成为 FAILED;策略化业务重试在 P3 实现。
|
||||
Run 的重连恢复同一次控制操作。平台的 [安全重试](../api/retries.md) 使用同一 Task.ID 派发新的 AttemptID/Epoch,运行器按新的有效授权调用处理器,预算与退避由服务端持久化管理。
|
||||
|
||||
## 5. 结果与错误分类
|
||||
|
||||
| 处理器结果 | SDK 报告 / 服务端行为 |
|
||||
| --- | --- |
|
||||
| 合法非 null JSON + nil error | SUCCEEDED |
|
||||
| `&orbit.WorkerFailure{Code:"OBJECT_REJECTED", Details:...}` | FAILED;仅用于能确认的业务失败,Details 为空时为 `{}` |
|
||||
| 普通 error | UNKNOWN / HANDLER_ERROR,进入 NEEDS_REVIEW |
|
||||
| `&orbit.WorkerFailure{Code:"OBJECT_REJECTED", Details:...}` | FAILED;默认 Retryable=false,Details 为空时为 `{}` |
|
||||
| `&orbit.WorkerFailure{Code:"TEMPORARY_REJECTION", Retryable:true}` | 明确失败可安全重试,平台仍核验次数、总时限和历史不确定效果 |
|
||||
| 普通 error | UNKNOWN / HANDLER_ERROR;默认转核查,仅 IDEMPOTENT 且预算允许时可自动重试 |
|
||||
| panic / runtime.Goexit | UNKNOWN / HANDLER_PANIC 或 HANDLER_ABORTED |
|
||||
| 非法 JSON、超限结果、不支持数值或嵌套 | UNKNOWN / INVALID_HANDLER_RESULT |
|
||||
| 处理器因租约取消返回错误 | UNKNOWN / LEASE_LOST |
|
||||
@@ -94,7 +95,7 @@ Run 的重连是控制消息恢复,不是业务自动重试。当前明确失
|
||||
|
||||
原始异常和 panic 内容不写入结果或通知。Result/Details 最多 256 KiB,应优先使用对象引用。SDK 保留精确数字文本,并按服务端数字范围及完整帧的嵌套上限预检,避免产生永远无法接受的报告。
|
||||
|
||||
普通网络错误不能证明副作用未发生,因此不会自动解释为明确失败。UNKNOWN 和迟到证据的后续核查由平台管理能力与业务对账共同处理。
|
||||
普通网络错误不能证明副作用未发生,因此不会自动解释为明确失败。UNKNOWN 由服务端结合真实幂等声明决定是否重试;迟到证据不能清除历史不确定效果。完整规则及可运行示例见 [安全重试](../api/retries.md)。
|
||||
|
||||
## 6. 退出与故障边界
|
||||
|
||||
@@ -102,7 +103,7 @@ Run 的重连是控制消息恢复,不是业务自动重试。当前明确失
|
||||
|
||||
ShutdownTimeout 从取消信号发生时开始计时,包含网络等待和处理器收尾。到期后取消控制请求及处理器 context,返回 `*WorkerRunError`;可用 `errors.Is(err, orbit.ErrWorkerShutdownTimeout)` 判断,Unconfirmed 和 Running 给出终止收尾时的快照。其他致命错误也带这些计数,便于识别未核对的执行。
|
||||
|
||||
Go 无法杀死忽略 context 的 goroutine。Run 可以有界返回,但这类函数可能仍在进程中执行;不得把返回错误解释为副作用已停止,也不要在同一进程盲目重建 Worker 叠加执行。服务端对失联执行按租约回收并进入核查。
|
||||
Go 无法杀死忽略 context 的 goroutine。Run 可以有界返回,但这类函数可能仍在进程中执行;不得把返回错误解释为副作用已停止,也不要在同一进程盲目重建 Worker 叠加执行。服务端对失联执行按租约回收,依冻结安全策略决定重试或进入核查。
|
||||
|
||||
身份、尚未确认的结果和消息 ID 当前保存在内存,支持同进程重连;进程被强杀会失去这些内容。持久化租约、操作回执、最终结果和审计在 MySQL 中,业务外部效果仍需要业务幂等或查询核对。这一边界不等于端到端 exactly-once。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user