feat: configure graceful shutdown window

This commit is contained in:
2026-09-20 20:07:32 +08:00
parent c3e9610258
commit a557ba5af0
11 changed files with 32 additions and 13 deletions

View File

@@ -37,11 +37,11 @@ curl -fsS http://127.0.0.1:8080/health/ready
`live` 只表示进程仍在运行;`ready` 同时核对 MySQL、迁移账本和零外键要求。收到 `503` 时停止向该节点发送新的受理、执行授权和流程推进请求,保留原幂等键并等待核对,不把网络错误当作业务失败。
后台调度默认每秒检查 Weave 和计划、每两秒执行一次执行恢复,每批最多处理100条持久化候选。容量验证后可以通过 `ORBIT_WORKFLOW_TICK_INTERVAL`、`ORBIT_SCHEDULE_TICK_INTERVAL`、`ORBIT_RECOVERY_TICK_INTERVAL` 和 `ORBIT_RUNTIME_BATCH_LIMIT` 调整;间隔只允许 `100ms` 到 `1m`,批量只允许 `1` 到 `100`。调优必须和数据库锁等待、连接池、积压及恢复窗口一起记录,不能只提高批量或缩短间隔来掩盖容量不足。
后台调度默认每秒检查 Weave 和计划、每两秒执行一次执行恢复,每批最多处理100条持久化候选。容量验证后可以通过 `ORBIT_WORKFLOW_TICK_INTERVAL`、`ORBIT_SCHEDULE_TICK_INTERVAL`、`ORBIT_RECOVERY_TICK_INTERVAL` 和 `ORBIT_RUNTIME_BATCH_LIMIT` 调整;间隔只允许 `100ms` 到 `1m`,批量只允许 `1` 到 `100`。`ORBIT_SHUTDOWN_TIMEOUT` 控制 SIGTERM 后的排空和优雅关闭窗口,允许 `1s` 到 `5m`,默认 `10s`。调优必须和数据库锁等待、连接池、积压及恢复窗口一起记录,不能只提高批量或缩短间隔来掩盖容量不足。
## 3. 滚动停止与替换
Orbit 接收到 `SIGTERM` 后停止新的 Worker/Event 连接,取消后台循环,关闭 HTTP/WS 监听并在有限时间内等待已有连接退出。发布脚本应按以下顺序操作:
Orbit 接收到 `SIGTERM` 后停止新的 Worker/Event 连接,先将 readiness 置为 `503`,再取消后台循环、关闭 HTTP/WS 监听,并按 `ORBIT_SHUTDOWN_TIMEOUT` 等待已有连接退出。发布脚本应按以下顺序操作:
1. 从服务发现或负载均衡中摘除目标节点,等待健康检查不再分配新流量。
2. 向进程发送 `SIGTERM`,等待进程退出;超过发布窗口时记录进程和连接状态,再按值班策略处理。

View File

@@ -53,6 +53,7 @@ docker run --rm \
--env ORBIT_WORKFLOW_TICK_INTERVAL=1s \
--env ORBIT_SCHEDULE_TICK_INTERVAL=1s \
--env ORBIT_RECOVERY_TICK_INTERVAL=2s \
--env ORBIT_SHUTDOWN_TIMEOUT=10s \
--env ORBIT_METRICS_ADDR=127.0.0.1:9090 \
--publish 8080:8080 \
registry.example/orbit:dev

View File

@@ -46,6 +46,7 @@ curl -fsS http://127.0.0.1:9090/metrics
| `orbit_runtime_batch_last_success_timestamp_seconds` | gauge | 最后一次无错误批次返回的Unix时间;启动后未成功时为0 |
| `orbit_runtime_tick_interval_seconds{component}` | gauge | 节点实际生效的后台扫描间隔,component为workflow、schedule、execution_recovery |
| `orbit_runtime_batch_limit` | gauge | 节点实际生效的后台批量上限 |
| `orbit_shutdown_timeout_seconds` | gauge | 节点实际生效的排空与优雅关闭窗口(秒) |
| `orbit_db_connections_open` / `orbit_db_connections_in_use` / `orbit_db_connections_idle` | gauge | 本节点MySQL连接池当前连接数 |
| `orbit_db_connections_max_open` | gauge | 池配置的最大连接数 |
| `orbit_db_wait_count_total` / `orbit_db_wait_duration_seconds_total` | counter | 连接池累计等待次数/秒数,不是数据库锁等待 |

View File

@@ -8,8 +8,8 @@
| --- | --- | --- |
| 就绪探针排空门控 | `go test -race ./internal/transport/httpserver ./cmd/orbit`;`TestReadinessEntersDrainBeforeShutdown` | PASS;SIGTERM 关闭路径先将 `/health/ready` 置为 503,再进入限定优雅关闭窗口;响应不泄露内部错误 |
| 服务端单元与竞态、vet、构建 | Docker `golang:1.27.1`,仓库声明版本;`GOWORK=off go test -race ./... && go vet ./... && go build ./...` | PASS |
| 后台运行参数边界 | `internal/config.TestRuntimeDefaultsAndBoundedOverrides`;默认值与四个 `ORBIT_*` 覆盖项 | PASS;循环间隔限定100ms–1m,批量限定1–100,服务启动日志记录生效值 |
| 生效运行参数指标 | `internal/observability.TestRuntimeObservationDoesNotExposeErrors`;固定指标目录 | PASS;workflow/schedule/execution_recovery 间隔和批量上限以固定基数指标导出,不进入业务或租户标签 |
| 后台运行参数边界 | `internal/config.TestRuntimeDefaultsAndBoundedOverrides`;默认值与五个 `ORBIT_*` 覆盖项 | PASS;循环间隔限定100ms–1m,批量限定1–100,排空超时限定1s–5m,服务启动日志记录生效值 |
| 生效运行参数指标 | `internal/observability.TestRuntimeObservationDoesNotExposeErrors`;固定指标目录 | PASS;workflow/schedule/execution_recovery 间隔、批量上限和排空超时以固定基数指标导出,不进入业务或租户标签 |
| SDK 与独立示例竞态、vet、构建 | Docker `golang:1.27.1`;SDK 全 module、全部示例、`orbit-load`、`orbit-exec-load`、`orbit-schedule-load`、`orbit-workflow-load`,以及 result-inbox/task-outbox | PASS;健康/版本 SDK 契约包含 `Client.Version(ctx)`,返回协议身份且不暴露敏感响应 |
| 容器发布物构建 | `make image`;宿主平台 linux/arm64;显式 `docker build --platform linux/amd64`;带 `VERSION`、`REVISION`、`BUILD_TIME` 构建参数的版本化镜像;镜像内 `GOWORK=off` | PASS;native 与 amd64 镜像均构建成功,包含 `orbit`、`orbit-migrate`、`orbit-admin`,运行用户为非 root;版本化 amd64 二进制和 OCI 标签均包含注入的构建身份,`GET /version` 契约单测通过;无 DSN 时服务按预期拒绝启动 |
| 当前协议门禁 | `make protocol-check` | PASS,当前 v1 契约同步 |