feat: add bounded workflow execution measurement
This commit is contained in:
@@ -62,7 +62,7 @@ P4/P5定时等待与后续查询轮次的实现及回归记录见[时钟报告](
|
||||
2. 已实现[基础运行观测](api/observability.md)及[有界业务状态与事件采样](reports/phase-6-business-observability.md):HTTP/WS、数据库连接池、后台批次、固定任务/交付/流程/Inbox状态计数、最近事件类别、终态耗时样本、固定事件阶段耗时、最早年龄、截断/新鲜度指标和可离线验证的告警规则;独立采集监听默认关闭,固定指标目录拒绝动态标签;发布前只读结构核验由[`orbit-admin verify`](api/operations.md)提供,运维人员也可用 `orbit-admin observe snapshot` 获取同一有界单节点快照。仍需端到端外部效果延迟、全局持久吞吐、Inbox从事件产生到推进完成的精确阶段延迟、全局发送队列、多节点聚合及生产采集/通知验证。
|
||||
3. 已补齐受保护管理环境中的固定凭据操作文件、轮换、撤销、幂等回执和脱敏管理审计;轮换保留授权绑定并要求新令牌重新建立会话,旧 Worker 会话被排空且立即过期,撤销允许在停用范围内执行且不改写历史记录。已用一次性 MySQL 定向验证旧令牌失效、新令牌重绑和零外键;仍需补齐提交不明故障切点、多节点安全重绑演练、凭据最小权限配置核对和生产密钥托管/审计演练。
|
||||
4. 已补[`orbit-admin retention inventory`](api/retention.md)只读盘点和[阶段报告](reports/phase-6-retention-inventory.md),能区分过期幂等、确定终态、未知效果、未终结流程、已确认/未确认交付、已消费/未消费Inbox、事件和审计规模;它不执行归档或删除。后续仍需评审各类保留周期、归档格式、受保护记录核对,再执行备份恢复、兼容升级和六类容量负载。未确认交付、有效幂等身份、当前/历史执行证据和未终结流程不能被普通清理破坏。生产HA及RPO/RTO继续按实际拓扑验证,不缩减为本机多进程检查。
|
||||
5. 已补[`orbit-load`](api/load.md)有界受理负载工具及24次/1000次隔离样本,见[受理报告](reports/phase-6-load.md)。新增独立[`orbit-exec-load`](api/execution-load.md),通过真实Worker、任务结果和尝试历史核对,提供短/混合/中长任务的受理、排队、授权执行及完成耗时分布;具体环境、原始JSON和失败分母见[执行测量报告](reports/phase-6-execution-load.md)。标准Go 1.27.1全量仍待复跑,下一步补定时集中触发、Weave流程推进、长期积压和资源曲线;目标数据库拓扑容量仍单独验收。
|
||||
5. 已补[`orbit-load`](api/load.md)有界受理负载工具及24次/1000次隔离样本,见[受理报告](reports/phase-6-load.md)。新增独立[`orbit-exec-load`](api/execution-load.md),通过真实Worker、任务结果和尝试历史核对,提供短/混合/中长任务的受理、排队、授权执行及完成耗时分布;具体环境、原始JSON和失败分母见[执行测量报告](reports/phase-6-execution-load.md)。新增[`orbit-workflow-load`](api/workflow-load.md),用固定版本的双分支并行流程核对步骤、来源、尝试和输出,见[流程测量报告](reports/phase-6-workflow-load.md)。标准Go 1.27.1全量仍待复跑,下一步补定时集中触发、长期积压和资源曲线;目标数据库拓扑容量仍单独验收。
|
||||
6. 已补[隔离备份恢复演练](api/backup-restore.md):源库和恢复库均为一次性 MySQL 容器,逻辑备份恢复后核对迁移账本、核心记录数量、固定索引和零外键;证据见[恢复报告](reports/phase-6-backup-restore.md)。该演练不替代生产备份介质、复制切换、跨版本恢复或 RPO/RTO 验收。
|
||||
7. 已补[A18 数据库短暂不可用恢复演练](api/db-recovery.md):readiness 在数据库停止期间返回 503,同卷恢复后返回 200,并用原权限范围继续受理任务;证据见[数据库恢复报告](reports/phase-6-db-recovery.md)。该演练不替代主从切换、复制确认、跨故障域或 RPO/RTO 验收。
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
| `orbit-admin retention inventory` 保留清单 | 已实现带 UTC 截止时间的只读盘点;不执行归档、删除或权限变更 | [保留清单](retention.md) |
|
||||
| `sdk/go/cmd/orbit-load` 有界受理负载工具 | 已实现固定并发、无自动重试、延迟百分位和错误分类;只用于隔离环境 | [负载工具](load.md) |
|
||||
| `sdk/go/cmd/orbit-exec-load` 有界任务执行测量 | 已实现真实Worker、固定混合时长、最终结果/尝试核验及阶段耗时分布 | [执行测量](execution-load.md) |
|
||||
| `sdk/go/cmd/orbit-workflow-load` 有界流程执行测量 | 已实现固定版本、双分支并行、真实Worker、步骤/来源/尝试/输出核验及阶段耗时分布 | [流程测量](workflow-load.md) |
|
||||
| `scripts/test-backup-restore.sh` 隔离备份恢复演练 | 已实现一次性 MySQL 逻辑备份、独立恢复、核心计数及零外键核验 | [备份恢复演练](backup-restore.md) |
|
||||
| `scripts/test-db-recovery.sh` MySQL 短暂不可用恢复演练 | 已实现 readiness 503、同卷恢复 200 及恢复后任务受理核验 | [数据库恢复演练](db-recovery.md) |
|
||||
| `/v1/worker/connect` | P2 已实现并通过阶段验收 | [Worker 契约](worker.md)、[Schema](worker-schema.md) |
|
||||
|
||||
35
docs/api/workflow-load.md
Normal file
35
docs/api/workflow-load.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# Weave 流程负载测量工具
|
||||
|
||||
`orbit-workflow-load` 是 SDK 模块中的隔离测量命令,用于验证一条真实的 Weave 流程链路:创建定义、发布不可变 `v1`、启动多个实例、由独立 WSS Worker 执行两个有限并行分支,再核对持久化流程、步骤、任务、尝试、任务来源和最终输出。
|
||||
|
||||
它只使用 Orbit HTTP/WSS 和 MySQL 服务端已有能力,不连接消息队列、缓存或业务数据库;处理器只回显固定输入,不产生外部业务副作用。工具不会自动重试写请求,响应不明时必须保留原运行身份,通过报告中的分母定位未确认实例。
|
||||
|
||||
## 使用
|
||||
|
||||
先为隔离命名空间签发包含 `workflow-access`、`workflow-run-access` 与 `worker-access` 的凭据文件,再执行:
|
||||
|
||||
```sh
|
||||
ORBIT_URL=https://orbit.example.test \
|
||||
ORBIT_CREDENTIALS_FILE=/run/secrets/orbit-load.json \
|
||||
go run ./cmd/orbit-workflow-load \
|
||||
-requests 100 \
|
||||
-concurrency 8 \
|
||||
-workers 2 \
|
||||
-capacity 4 \
|
||||
-run-timeout 5m \
|
||||
-poll-interval 250ms
|
||||
```
|
||||
|
||||
参数上限是 `requests<=2000`、启动/核验并发 `<=128`、Worker 数 `<=32`、单 Worker 容量 `<=256` 且总容量 `<=1024`。`-timeout` 是单次 HTTP 交换截止,`-run-timeout` 是整次样本截止;两者都不是生产系统的 SLA。
|
||||
|
||||
工具先只读核对队列,不修改队列额度;定义名、实例幂等键、业务键和处理器名都带一次运行生成的随机前缀。每个实例固定使用输入 `{"run_id":"...","sequence":N}`,流程输出必须同时包含 `left` 和 `right` 两个相同对象。
|
||||
|
||||
## 报告解释
|
||||
|
||||
输出为一行 JSON,包含 `attempted`、`accepted`、`verified_success`、`unverified`、`handler_calls`、`worker_started`、`errors` 及 `admission`/`completion` 百分位。`complete=true` 的必要条件是:全部启动调用有唯一回执、全部实例为 `SUCCEEDED`、每个流程恰有两个成功 TASK 步骤、每个任务恰有一次成功尝试、来源固定到同一实例和版本、两倍分支处理器调用全部被确认且没有重复调用。
|
||||
|
||||
任何预检、发布、启动、读取、步骤、尝试、来源或截止错误都会保留稳定错误分类并以非零状态退出。空分布的百分位是 JSON `null`,不能解释成零延迟。`completion` 是服务端 `created_at` 到 `completed_at` 的持久化耗时;它不是客户端轮询耗时。
|
||||
|
||||
## 验证边界
|
||||
|
||||
该工具适合在一次性 MySQL、测试凭据和明确的资源上限下做正确性、故障分母和阶段延迟验证。单机样本不能证明多节点吞吐、跨故障域高可用、备份恢复、RPO/RTO 或面向生产的容量;生产验收还需要目标拓扑、数据规模、连接池、备份介质、监控采集和发布兼容矩阵的独立证据。
|
||||
@@ -38,7 +38,7 @@
|
||||
|
||||
| 项目 | 必须提供的证据 | 状态 |
|
||||
| --- | --- | --- |
|
||||
| 受理、派发、流程推进和恢复吞吐 | 固定硬件、数据量、任务/流程混合模型,p50/p95/p99和资源曲线 | 已有受理样本及[真实Worker短/混合/中长执行样本](reports/phase-6-execution-load.md);定时/流程/积压/资源曲线和目标生产容量未验收 |
|
||||
| 受理、派发、流程推进和恢复吞吐 | 固定硬件、数据量、任务/流程混合模型,p50/p95/p99和资源曲线 | 已有受理样本、[真实Worker短/混合/中长执行样本](reports/phase-6-execution-load.md)及[Weave双分支流程样本](reports/phase-6-workflow-load.md);定时/积压/资源曲线和目标生产容量未验收 |
|
||||
| 100万+企业规模推导 | 租户、队列、连接、事件、索引和保存周期的容量模型 | 未验收,不能由租户数直接推导 |
|
||||
| MySQL 复制、切换、RPO/RTO | 目标拓扑上的实际切换、复制确认、恢复点和恢复时间 | 未验收 |
|
||||
| 慢消费者、重连风暴、磁盘和锁等待 | 受控故障负载及积压清空证据 | 未验收 |
|
||||
|
||||
40
docs/reports/data/phase-6-workflow-load/environment.json
Normal file
40
docs/reports/data/phase-6-workflow-load/environment.json
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"date_local": "2026-09-20",
|
||||
"timezone": "Asia/Shanghai",
|
||||
"test_go": "go1.25.14",
|
||||
"declared_go": "1.27.1",
|
||||
"temporary_modfile": true,
|
||||
"mysql": "8.4.10",
|
||||
"docker_vm_cpus": 12,
|
||||
"docker_vm_memory_bytes": 12529274880,
|
||||
"architecture": "arm64",
|
||||
"orbit_processes": 1,
|
||||
"mysql_nodes": 1,
|
||||
"worker_processes": 1,
|
||||
"worker_connections_normal": 2,
|
||||
"worker_capacity_each": 4,
|
||||
"workflow_requests": 24,
|
||||
"workflow_concurrency": 6,
|
||||
"queue_max_concurrency": 4,
|
||||
"queue_rate_per_second": 10,
|
||||
"poll_interval_ms": 100,
|
||||
"http_timeout_ms": 5000,
|
||||
"run_timeout_ms": 90000,
|
||||
"metrics_enabled": false,
|
||||
"cpu_memory_limits": "No dedicated limits; shared local Docker VM, other workloads possible",
|
||||
"fresh_disposable_database": true,
|
||||
"network": "Go runner shares MySQL container network namespace; loopback HTTP/WSS and MySQL",
|
||||
"schema_verification": {
|
||||
"schema_version": 28,
|
||||
"migration_count": 28,
|
||||
"foreign_key_count": 0,
|
||||
"required_index_count": 6,
|
||||
"complete": true
|
||||
},
|
||||
"source_sha256": {
|
||||
"sdk/go/cmd/orbit-workflow-load/main.go": "05a160431b26d91ab430392b23f4fcf76bd23dfeb21bd2047fe8372c17e93fe5",
|
||||
"sdk/go/cmd/orbit-workflow-load/measure.go": "1a31d06d3a9e483aee5aca115f7f1230649e050a0bddae1770659fe2735a99a3",
|
||||
"sdk/go/cmd/orbit-workflow-load/measure_test.go": "42e710139f515aa339b5684107d00fcb413688e7512fc4c36ebfe56776ad41a1",
|
||||
"sdk/go/cmd/orbit-workflow-load/report.go": "701a27a3f4f56cf9566fbcf97fba8024ced36b32754f4a5dcdae4646a2a4b24a"
|
||||
}
|
||||
}
|
||||
1
docs/reports/data/phase-6-workflow-load/sample-24.json
Normal file
1
docs/reports/data/phase-6-workflow-load/sample-24.json
Normal file
@@ -0,0 +1 @@
|
||||
{"run_id":"e4f954ba8507b35fda519f197c301304","go_version":"go1.25.14","goos":"linux","goarch":"arm64","started_at":"2026-09-19T18:55:18.343555301Z","admission_finished_at":"2026-09-19T18:55:18.553077926Z","finished_at":"2026-09-19T18:55:33.351706711Z","requests":24,"concurrency":6,"workers":2,"capacity_per_worker":4,"run_timeout_ms":90000,"poll_interval_ms":100,"http_timeout_ms":5000,"queue":{"max_unfinished_tasks":100000,"unfinished_tasks":"0","id":"6ba1b31c689aa7249f9f41bc873b3a6f","namespace_id":"5dd105847384f7782a1923aa4288508e","name":"workflow","paused":false,"max_concurrency":4,"rate_per_second":10,"revision":"1"},"definition_id":"5650b9f2a6838263ea3222dd879f6540","version_id":"73608bdb26c948a98700d101c1f5e787","attempted":24,"not_submitted":0,"accepted":24,"admission_errors":0,"verified_success":24,"unverified":0,"handler_calls":48,"duplicate_invocations":0,"worker_started":48,"worker_reconnects":0,"worker_renewals_confirmed":0,"admission":{"count":24,"p50_ms":44.767208,"p95_ms":49.584459,"p99_ms":56.462333,"max_ms":56.462333},"completion":{"count":24,"p50_ms":7898.658,"p95_ms":13838.444,"p99_ms":14788.909,"max_ms":14788.909},"errors":{},"complete":true}
|
||||
41
docs/reports/phase-6-workflow-load.md
Normal file
41
docs/reports/phase-6-workflow-load.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# P6 Weave 流程执行测量
|
||||
|
||||
验证日期:2026-09-20(UTC 运行时间记录为 2026-09-19 18:51)。这是一次性 MySQL 8.4 容器中的隔离正确性与阶段延迟样本,不是生产容量或高可用验收。
|
||||
|
||||
## 测量内容
|
||||
|
||||
`orbit-workflow-load` 通过独立 Go SDK 完成以下链路:
|
||||
|
||||
1. 只读检查队列状态。
|
||||
2. 创建一个新的稳定定义并发布不可变 `v1`。
|
||||
3. 启动 24 个独立实例,每个实例使用自己的幂等键和业务键。
|
||||
4. 每个实例执行一个包含 `left`、`right` 两个静态分支的 `PARALLEL` 节点;两个分支各创建一个 `TASK`。
|
||||
5. 两个真实 WSS Worker(每个容量4)回显固定输入。
|
||||
6. 对每个成功实例读取步骤、任务、唯一尝试、流程任务来源和最终输出,核对实例固定版本及来源归属。
|
||||
|
||||
处理器只回显 `run_id` 和 `sequence`,没有外部副作用;启动调用和流程读取都没有 SDK 自动重试。流程定义把任务尝试上限固定为1,响应不明时保留原运行身份。
|
||||
|
||||
## 实际结果
|
||||
|
||||
| 项目 | 结果 |
|
||||
| --- | ---: |
|
||||
| 计划/实际启动调用 | 24 / 24 |
|
||||
| 唯一受理实例 | 24 |
|
||||
| 持久化核验成功 | 24 |
|
||||
| 未核验实例 | 0 |
|
||||
| 处理器调用 | 48(每实例两个分支) |
|
||||
| 重复调用 | 0 |
|
||||
| Worker 启动任务数 | 48 |
|
||||
| 错误分类 | 空 |
|
||||
| 完成标记 | `true` |
|
||||
| 启动耗时 P50 / P95 / P99 | 44.767208 / 49.584459 / 56.462333 ms |
|
||||
| 服务端流程完成耗时 P50 / P95 / P99 / Max | 7898.658 / 13838.444 / 14788.909 / 14788.909 ms |
|
||||
|
||||
原始 JSON:[sample-24.json](data/phase-6-workflow-load/sample-24.json),工具链和源码摘要见[环境清单](data/phase-6-workflow-load/environment.json)。执行工具和字段语义见[流程负载测量手册](../api/workflow-load.md)。
|
||||
|
||||
## 环境和边界
|
||||
|
||||
- 负载工具:Go `1.25.14`,Linux `arm64`;请求并发6,Worker 2×4,轮询100ms,单次 HTTP 5s,整次样本90s。
|
||||
- 服务端:一次性 Docker MySQL `8.4`,通过当前迁移器初始化;结束时 `orbit-admin verify` 输出 `schema_version=28`、`migration_count=28`、`foreign_key_count=0`、`required_index_count=6`、`complete=true`。
|
||||
- 队列为只读测试资源,`max_concurrency=4`、`rate_per_second=10`;队列额度和数据库结构没有因测量修改。
|
||||
- 该样本证明流程发布、并行推进、Worker 执行、持久化回执和来源核对在此环境可复现;它不证明多节点吞吐、跨故障域恢复、生产连接池容量、RPO/RTO、备份介质或市场化部署 SLA。
|
||||
@@ -8,7 +8,7 @@
|
||||
| --- | --- | --- |
|
||||
| 服务端单元与竞态 | Docker `golang:1.25`,临时 modfile;`GOWORK=off go test -race ./...` | PASS |
|
||||
| 服务端 vet | Docker `golang:1.25`;`GOWORK=off go vet ./...` | PASS |
|
||||
| SDK 竞态、vet、构建 | Docker `golang:1.25`;SDK 全 module、全部示例和 `orbit-load` | PASS |
|
||||
| SDK 竞态、vet、构建 | Docker `golang:1.25`;SDK 全 module、全部示例、`orbit-load`、`orbit-exec-load` 和 `orbit-workflow-load` | PASS |
|
||||
| 当前协议门禁 | `make protocol-check` | PASS,当前 v1 契约同步 |
|
||||
| 外键迁移防回归 | `TestPostRemovalMigrationGuard`;服务端迁移运行时校验 | PASS;000008 以前仅保留兼容清理历史,后续迁移在执行前拒绝引用约束 DDL |
|
||||
| MySQL 存储集成 | MySQL 8.4.10,一次性容器;`go test -race -run Integration -skip 'TestIntegration(WorkflowCommitFaults\|CredentialCommitFaults)$'` | PASS,210.893 秒;包含空库无外键基线、v7升级、Pulse/Weave/API/观测/恢复与W16竞争 |
|
||||
@@ -18,6 +18,7 @@
|
||||
| SDK 应用配额子进程故障 | 独立双命名空间应用配额凭据;共享网络命名空间;`TestIntegrationWorkerProcessApplicationBackpressure` | PASS,1.069 秒;重启后共享额度、原回执和跨命名空间背压保持 |
|
||||
| Orbit HTTP/metrics 子进程 | 同一共享网络命名空间;`TestIntegrationMetricsProcess`;metrics 启用/禁用各一组 | PASS,3.081 秒;监听隔离、隐私、后台采样和优雅退出均通过 |
|
||||
| 真实Worker执行测量 | `orbit-exec-load`;最终短/混合/中长及截止不足四组,环境及原始JSON见[测量报告](phase-6-execution-load.md) | 96+96+6项全部逐项核验,长任务18次续租;24项截止负例按预期非零退出。SDK全模块竞态/vet/build通过,生产容量未验收 |
|
||||
| 真实Weave流程测量 | `orbit-workflow-load`;24实例、固定版本双分支并行,原始JSON见[流程测量报告](phase-6-workflow-load.md) | 24/24实例成功,48/48任务尝试与来源、输出逐项核验,重复调用0;生产容量未验收 |
|
||||
|
||||
## 当前环境仍未覆盖
|
||||
|
||||
|
||||
Reference in New Issue
Block a user