27 Commits

Author SHA1 Message Date
f8c99f3e21 docs: record favicon deployment verification 2026-09-30 00:34:40 +08:00
d47d0d361d fix: add Orbit favicon to console and login pages 2026-09-30 00:33:24 +08:00
7d0de4f57a docs: record login protection and scrolling acceptance 2026-09-30 00:26:41 +08:00
f56f233704 fix: stabilize console scrolling and protect administrator login 2026-09-30 00:09:01 +08:00
9a15406f76 docs(console): record scroll stability deployment acceptance 2026-09-29 23:38:41 +08:00
23db3d8fe0 fix(console): stabilize workspace scrolling and background refresh 2026-09-29 23:36:57 +08:00
755cd2d3c3 docs(console): record filter and pagination deployment checks 2026-09-29 23:02:58 +08:00
df76dcb9c0 feat(console): refine filters and default resource pages to ten rows 2026-09-29 23:00:53 +08:00
96d5a3032a docs(console): record browser and local deployment acceptance 2026-09-29 22:33:54 +08:00
92a40f4a37 fix(console): preserve destination through initial login redirect 2026-09-29 22:32:28 +08:00
f7409afd24 feat(console): simplify workspace and add filtered resource pagination 2026-09-29 22:31:19 +08:00
6138c103d5 docs: record v0.1.2 remote SDK and deployment acceptance 2026-09-27 14:52:00 +08:00
7b6f3ac60c chore: finalize resource retirement release verification 2026-09-27 14:49:48 +08:00
c9e877c3f7 feat: add generic queue and subscription retirement 2026-09-27 14:39:49 +08:00
d54bdd9847 feat: let administrators view and copy encrypted integration credentials 2026-09-27 13:48:26 +08:00
5555a7b342 docs: verify credential guidance and local integration setup 2026-09-27 13:05:51 +08:00
0782b0488b fix: make credential lookup and blocked rotation guidance actionable 2026-09-27 12:45:46 +08:00
e3d8b16844 fix: explain credential rotation grace period in console 2026-09-27 12:38:20 +08:00
c2ca5e987f docs: complete console application scope acceptance and deployment guidance 2026-09-27 12:29:31 +08:00
1f2e7230dc feat: show application ownership and scoped console management 2026-09-27 12:12:46 +08:00
ed17713ea1 docs: keep credential acceptance results in one table 2026-09-27 11:54:01 +08:00
4eeafdef41 docs: record credential rollover regression and local rollout 2026-09-27 11:53:39 +08:00
385a618154 feat: support permanent credentials and overlapping token rotation 2026-09-27 11:45:15 +08:00
87aa710013 feat: add single-admin application onboarding and token rotation 2026-09-27 10:18:31 +08:00
98ff028228 feat: add persistent local Compose integration environment 2026-09-27 09:35:49 +08:00
2ec13bf662 docs: record v0.1.1 remote installation verification 2026-09-24 21:29:04 +08:00
81e56bd633 docs: consolidate runnable examples and publish v0.1.1 guides 2026-09-24 21:27:25 +08:00
229 changed files with 8735 additions and 815 deletions

View File

@@ -7,3 +7,8 @@ sdk
examples examples
deploy deploy
*.log *.log
.local
.env
.env.*
!.env.example
**/*.credentials.json

View File

@@ -1,5 +1,7 @@
# Example only. Load environment variables explicitly; binaries do not read .env. # Example only. Load environment variables explicitly; binaries do not read .env.
ORBIT_HTTP_ADDR=127.0.0.1:8080 ORBIT_HTTP_ADDR=127.0.0.1:8080
# 控制台默认队列,不替代登录及账号授权。
ORBIT_CONSOLE_QUEUE_ID=
# Set a real DSN through your secret manager. No credentials are committed. # Set a real DSN through your secret manager. No credentials are committed.
ORBIT_MYSQL_DSN= ORBIT_MYSQL_DSN=
ORBIT_DB_MAX_OPEN=20 ORBIT_DB_MAX_OPEN=20

View File

@@ -85,7 +85,7 @@
- P6进程观测使用internal/observability固定指标目录,拒绝未知名称、类型和动态标签,不能引入任务/租户/业务键/凭据维度。ORBIT_METRICS_ADDR默认空(关闭),显式启用独立采集监听;业务端口不得暴露全局指标。渲染和网络I/O不持有全局记录锁,每个直方图局部快照保持桶/count/sum一致,最多2个并发抓取。启用指标后的5秒后台采样使用000026–000028固定索引读取任务、交付、流程状态、Weave Inbox状态、固定事件类别、终态耗时和最近窗口内固定事件阶段耗时,每个状态或事件最多10000条、事件窗口5分钟、900ms数据库截止;采样失败保留最后成功状态并独立记录错误/超时,不能影响业务事务或把有限样本当全局精确数。 - P6进程观测使用internal/observability固定指标目录,拒绝未知名称、类型和动态标签,不能引入任务/租户/业务键/凭据维度。ORBIT_METRICS_ADDR默认空(关闭),显式启用独立采集监听;业务端口不得暴露全局指标。渲染和网络I/O不持有全局记录锁,每个直方图局部快照保持桶/count/sum一致,最多2个并发抓取。启用指标后的5秒后台采样使用000026–000028固定索引读取任务、交付、流程状态、Weave Inbox状态、固定事件类别、终态耗时和最近窗口内固定事件阶段耗时,每个状态或事件最多10000条、事件窗口5分钟、900ms数据库截止;采样失败保留最后成功状态并独立记录错误/超时,不能影响业务事务或把有限样本当全局精确数。
- HTTP成功升级在Hijack完成时记录握手,WS处理器存续计入独立连接指标;保持1xx临时响应、Flush、Hijack与原panic行为。DB池取本地Stats,抓取不查询业务库;后台批次success不是业务任务成功量。观测丢样或失败不得改变权威事务及恢复决定。 - HTTP成功升级在Hijack完成时记录握手,WS处理器存续计入独立连接指标;保持1xx临时响应、Flush、Hijack与原panic行为。DB池取本地Stats,抓取不查询业务库;后台批次success不是业务任务成功量。观测丢样或失败不得改变权威事务及恢复决定。
- 进程指标、固定状态采样、格式验证、告警规则和标准回归证据见docs/reports/phase-6-observability.md及docs/reports/phase-6-business-observability.md。仍须补受理/授权/完成与流程推进延迟、持久吞吐/积压的全局聚合、重试/核查/恢复量、发送队列、实际采集告警及负载开销,不能把进程观测通过写成P6已完成。普通清理仍须保护有效幂等、未确认事件、未知结果和未终结流程。 - 进程指标、固定状态采样、格式验证、告警规则和标准回归证据见docs/reports/phase-6-observability.md及docs/reports/phase-6-business-observability.md。仍须补受理/授权/完成与流程推进延迟、持久吞吐/积压的全局聚合、重试/核查/恢复量、发送队列、实际采集告警及负载开销,不能把进程观测通过写成P6已完成。普通清理仍须保护有效幂等、未确认事件、未知结果和未终结流程。
- 凭据轮换保留credential_id及订阅/Worker授权绑定,在同一事务替换摘要、固定到期时间、幂等回执和管理审计;新令牌必须重新建立会话,认证路径每次重新核对凭据状态。撤销必须让认证失效并保留原任务、订阅、交付、会话和审计证据,允许在应用或命名空间停用后执行;重复应用同一固定操作幂等返回。管理CLI先把固定操作文件写成0600,再提交;提交不明时保留文件并用原文件重放,不能重新生成秘密。日志、审计摘要、指标和业务表不得保存秘密原文或摘要。不要把轮换同一凭据ID解释成历史令牌仍有效,也不得级联删除订阅、任务或事件。 - 凭据轮换保留credential_id及订阅/Worker授权绑定,在同一事务替换摘要、固定到期时间、幂等回执和管理审计;新令牌必须重新建立会话,认证路径每次重新核对凭据状态。撤销必须让认证失效并保留原任务、订阅、交付、会话和审计证据,允许在应用或命名空间停用后执行;重复应用同一固定操作幂等返回。管理CLI先把固定操作文件写成0600,再提交;提交不明时保留文件并用原文件重放,不能重新生成秘密。日志、审计摘要、指标和业务表不得保存秘密原文或摘要。000032 后仅在 previous_valid_until 之前接受上一代摘要(最长 30 天,不超过原到期时间);默认控制台/CLI过渡7天,旧固定v1操作仍立即轮换。默认新凭据长期有效;SET_EXPIRY 保持秘密不变,FINALIZE 停用旧代,REVOKE 同时停用两代;有效过渡期禁止再次轮换挤掉旧代。不要把稳定凭据ID解释成所有历史令牌仍有效,也不得级联删除订阅、任务或事件。
- `sdk/go/cmd/orbit-load` 只用于隔离环境受理测量:每项使用稳定独立幂等键,固定请求形状和并发上限,按请求超时,不自动重试,不启动Worker或执行外部副作用;输出延迟百分位与有限错误分类,失败必须以非零状态返回。其结果不能替代真实Worker、流程推进、数据库拓扑或生产容量验收。 - `sdk/go/cmd/orbit-load` 只用于隔离环境受理测量:每项使用稳定独立幂等键,固定请求形状和并发上限,按请求超时,不自动重试,不启动Worker或执行外部副作用;输出延迟百分位与有限错误分类,失败必须以非零状态返回。其结果不能替代真实Worker、流程推进、数据库拓扑或生产容量验收。
- `sdk/go/cmd/orbit-exec-load` 独立测量真实Worker执行:每次运行固定专属处理器/业务键/序号/模拟时长,最多一次尝试且无外部副作用;任务成功须核对持久化结果、唯一尝试、时间顺序及单次本地调用。队列额度只读,提交不重试;整体截止和有界排空后输出实际分母,未完成/未知结果必须非零退出。数据库阶段耗时不得混用客户端轮询观察时间,不将隔离样本解释为生产容量。 - `sdk/go/cmd/orbit-exec-load` 独立测量真实Worker执行:每次运行固定专属处理器/业务键/序号/模拟时长,最多一次尝试且无外部副作用;任务成功须核对持久化结果、唯一尝试、时间顺序及单次本地调用。队列额度只读,提交不重试;整体截止和有界排空后输出实际分母,未完成/未知结果必须非零退出。数据库阶段耗时不得混用客户端轮询观察时间,不将隔离样本解释为生产容量。
- `sdk/go/cmd/orbit-workflow-load` 独立测量真实Weave流程:每次运行创建固定版本的双分支并行定义,启动实例不自动重试,必须核对流程/步骤/任务/尝试/来源/输出及两倍分支调用;队列只读,处理器无外部副作用,截止后保留实际分母并以非零状态退出。隔离样本不代表生产容量、高可用或跨故障域验收。 - `sdk/go/cmd/orbit-workflow-load` 独立测量真实Weave流程:每次运行创建固定版本的双分支并行定义,启动实例不自动重试,必须核对流程/步骤/任务/尝试/来源/输出及两倍分支调用;队列只读,处理器无外部副作用,截止后保留实际分母并以非零状态退出。隔离样本不代表生产容量、高可用或跨故障域验收。
@@ -93,3 +93,7 @@
- `sdk/go/cmd/orbit-schedule-load` 使用同时起止的有限FIXED_RATE计划测量集中触发;固定版本/时区快照、触发时间槽、任务/尝试/来源、本地调用逐项核对。配置总数、已观察、已触发和已核验分开计数;截止保留原操作身份并有界暂停,不取消已生成任务;暂停只在明确版本冲突后换键,传输不明不得新键重试。样本不代表长期积压容量或生产HA。 - `sdk/go/cmd/orbit-schedule-load` 使用同时起止的有限FIXED_RATE计划测量集中触发;固定版本/时区快照、触发时间槽、任务/尝试/来源、本地调用逐项核对。配置总数、已观察、已触发和已核验分开计数;截止保留原操作身份并有界暂停,不取消已生成任务;暂停只在明确版本冲突后换键,传输不明不得新键重试。样本不代表长期积压容量或生产HA。
- 流程测量核验必须绑定本次发布的不可变版本ID及完整规范,步骤精确为pair/left/right且任务/激活唯一;按任务和尝试关联本地调用,不能用每实例总次数抵充缺失分支。零序号也要求精确必填字段,拒绝重复键/别名/null;报告保留逐请求原键与ID和未确认调用分母。源码更新后重新构建并运行真实样本,原二进制结果不得配上更新后的源码摘要。 - 流程测量核验必须绑定本次发布的不可变版本ID及完整规范,步骤精确为pair/left/right且任务/激活唯一;按任务和尝试关联本地调用,不能用每实例总次数抵充缺失分支。零序号也要求精确必填字段,拒绝重复键/别名/null;报告保留逐请求原键与ID和未确认调用分母。源码更新后重新构建并运行真实样本,原二进制结果不得配上更新后的源码摘要。
- 管理员接入信息按用户要求支持随时查看/复制当前 Token。000033 的 secret_key_id / secret_ciphertext 仅存 AES-256-GCM 密文,主密钥来自 ORBIT_CREDENTIAL_KEY_FILE,所有节点和管理 CLI 共用;不得记录秘密到日志/审计/幂等回执。查看须管理员会话、同源 POST、核对当前版本和摘要,并确认审计提交后才交付。历史导入只接受当前摘要,不接受过渡期旧代;不轮换身份、不改认证 revision/有效期/过渡截止。轮换原子替换密文,撤销清除密文;没有主密钥的旧 CLI 轮换必须清除过期密文。普通列表仅返回 token_stored,不自动读取秘密。
- 000034 通用退役不删除历史或回收名称,不含调用方业务判断。订阅退役按操作身份→结果流→订阅持锁,以提交水位核对未物化匹配结果、pending 与实际未确认交付;只有结清后才释放活动名额,暂停仍计入 64。队列退役按应用额度→身份→队列锁,保护未完成/未知任务、许可、活动计划、固定版本引用的活动流程及未退役订阅。所有新工作入口检查 retired_at,旧历史与原幂等回执仍可读取;旧写节点停止后迁移,禁止混跑忽略退役的服务端。

60
CHANGELOG.md Normal file
View File

@@ -0,0 +1,60 @@
# 版本记录
代码交付主分支为 `main`。采用 `v主版本.次版本.修订号`,已发布标签不可变;补丁按 `v0.1.1`、`v0.1.2` 递增,业务项目固定具体版本。
## main — 2026-09-29
- 登录增加 MySQL 持久失败计数、临时锁定、账号/IP 限流、可信代理解析与审计查询,阈值及时间可配置;迁移 000035,无外键。
- 补齐根页面和实际滚动区的边界回弹限制,修复侧栏与内容随触控板弹动。
- 修复长页面滚动体验:固定导航与页头、内容独立滚动,应用详情后台刷新避免重建相同快照及打断交互。
- 筛选范围改为可搜索的浅色菜单;四个资源列表默认每页 10 条,登录页大屏内容居中,统一筛选区与表格间距。
- 管理端统一浅色工作台、分组导航、紧凑总览、中文状态和移动端布局。
- 任务/流程增加服务端状态、精确业务键和时间筛选;任务、计划、流程、订阅增加游标分页、页大小与 ID 定位。刷新保留查询,迟到响应不覆盖新结果。
- 应用搜索、接入配置集中展示、低频操作折叠;详情支持复制 ID、键盘焦点与返回入口,Token 查看/复制及原有审计规则保持。
- 此前浅色工作台改版只更新控制台;本次登录保护增加管理接口与迁移 000035,业务 SDK 协议不变。SDK 继续使用 v0.1.2,Outbox 继续使用 v0.1.1。[验收记录](docs/reports/console-refresh.md)。
## v0.1.2 — 2026-09-27
- 通用队列/订阅永久退役、活动订阅名额释放、依赖与积压保护;历史、名称、审计和原幂等回执保留。
- SDK 新增 `RetireQueue` / `RetireSubscription`,新增完整接口文档和可运行资源生命周期示例。
- 应用接入页明确选择并记忆队列、展示暂停/退役和容量;未补存 Token 文案保持一致,禁止静默替换复制目标。
- 汇总 main 已交付的应用接入、默认长期凭据、有界新旧 Token 过渡和管理员加密保管/查看/复制能力。
服务端标签 `v0.1.2`、SDK 标签 `sdk/go/v0.1.2`;Outbox 未修改,继续使用 `adapters/outbox/mysql/v0.1.1`。服务端升级需停旧写节点、备份后前向迁移到 000034;旧 v0.1.1 SDK 的既有接口保持兼容,退役方法需要新 SDK。退役不删除数据,不代替生产环境容量与高可用验收。
验证范围见[资源退役报告](docs/reports/resource-retirement.md)。
## v0.1.1 — 2026-09-24
本版汇总 v0.1.0 之后已完成的控制台、运维和业务接入能力,并统一示例和接入文档。
### 新增及完善
- 控制台账号密码登录、页面访问保护、初始化管理员与登录页;前端自动使用同源服务地址。
- Compose 迁移/权限收紧/核验/启动链、域名反向代理示例及两节点部署覆盖配置。
- 可配置的历史保留策略、归档文件作业、周期归档计划及控制台作业管理。
- 跨节点重连、慢消费者、锁等待/死锁、增长与归档的隔离回归,详细范围见各验收报告。
- 独立 MySQL 事务 Outbox 适配包:调用方事务入队、受理确认钩子、持久预算与有界后台发送。
- 现有 HTTP 服务嵌入示例:业务事务 → Outbox → Worker → 可靠结果 → Inbox,含健康检查和有界关闭。
- 根 `examples/` 集中 27 个可运行场景,各有 README;首页按功能、启动、SDK、配置和运维组织。
### 版本与升级
| 发布物 | Git 标签 | 引用方式 |
| --- | --- | --- |
| 平台源码 | `v0.1.1` | 检出该标签构建服务端 |
| Go SDK | `sdk/go/v0.1.1` | `go get git.yuntuo.hk/k2safe/orbit/sdk/go@v0.1.1` |
| MySQL Outbox | `adapters/outbox/mysql/v0.1.1` | `go get git.yuntuo.hk/k2safe/orbit/adapters/outbox/mysql@v0.1.1` |
SDK 公共方法与 v0.1.0 保持一致,示例从 `sdk/go/examples/<name>` 移至 `examples/<name>`;原先 `cd sdk/go && go run ./examples/worker` 改为 `cd examples && go run ./worker`。示例不是业务导入包,核心 SDK 导入路径不变。
服务端数据库基线为 schema v31。已有数据库按[运行手册](docs/20-operations-runbook.md)备份、停旧写节点、执行前向迁移及 `orbit-admin verify`,然后启动新服务;不覆盖旧迁移文件。Outbox 表属于独立业务数据库,由业务迁移管理。
[本版发布核验](docs/reports/v0.1.1-release.md)记录本地回归、远端版本和外部项目安装结果。保留策略及归档不会自动删除源数据;生产跨故障域高可用和容量仍按[交付清单](docs/release-checklist.md)验收。
## v0.1.0
首个 SDK 接入版本,平台和 SDK 已使用不可变标签发布。远端安装与最初门禁证据见[首版发布报告](docs/reports/phase-7-sdk-remote-release.md)。

View File

@@ -1,9 +1,10 @@
GO ?= go GO ?= go
.PHONY: fmt test vet build adapters-check image integration console-e2e compose-check mysql-replication mysql-compatibility sdk-check protocol-check docs-check stability-check schedule-backlog release-manifest release-local-check .PHONY: fmt test vet build adapters-check image integration console-e2e console-check compose-check mysql-replication mysql-compatibility sdk-check protocol-check docs-check stability-check schedule-backlog release-manifest release-local-check
fmt: fmt:
$(GO) fmt ./... $(GO) fmt ./...
cd sdk/go && $(GO) fmt ./... cd sdk/go && $(GO) fmt ./...
cd examples && GOWORK=off $(GO) fmt ./...
cd examples/result-inbox && GOWORK=off $(GO) fmt ./... cd examples/result-inbox && GOWORK=off $(GO) fmt ./...
cd examples/task-outbox && GOWORK=off $(GO) fmt ./... cd examples/task-outbox && GOWORK=off $(GO) fmt ./...
cd adapters/outbox/mysql && GOWORK=off $(GO) fmt ./... cd adapters/outbox/mysql && GOWORK=off $(GO) fmt ./...
@@ -12,6 +13,7 @@ fmt:
test: test:
$(GO) test -race ./... $(GO) test -race ./...
cd sdk/go && $(GO) test -race ./... cd sdk/go && $(GO) test -race ./...
cd examples && GOWORK=off $(GO) test -race ./...
cd examples/result-inbox && GOWORK=off $(GO) test -race ./... cd examples/result-inbox && GOWORK=off $(GO) test -race ./...
cd examples/task-outbox && GOWORK=off $(GO) test -race ./... cd examples/task-outbox && GOWORK=off $(GO) test -race ./...
cd adapters/outbox/mysql && GOWORK=off $(GO) test -race ./... cd adapters/outbox/mysql && GOWORK=off $(GO) test -race ./...
@@ -20,12 +22,14 @@ test:
vet: vet:
$(GO) vet ./... $(GO) vet ./...
cd sdk/go && $(GO) vet ./... cd sdk/go && $(GO) vet ./...
cd examples && GOWORK=off $(GO) vet ./...
cd examples/result-inbox && GOWORK=off $(GO) vet ./... cd examples/result-inbox && GOWORK=off $(GO) vet ./...
cd examples/task-outbox && GOWORK=off $(GO) vet ./... cd examples/task-outbox && GOWORK=off $(GO) vet ./...
cd adapters/outbox/mysql && GOWORK=off $(GO) vet ./... cd adapters/outbox/mysql && GOWORK=off $(GO) vet ./...
cd examples/http-service && GOWORK=off $(GO) vet ./... cd examples/http-service && GOWORK=off $(GO) vet ./...
build: build:
cd examples && GOWORK=off $(GO) build ./...
cd adapters/outbox/mysql && GOWORK=off $(GO) build ./... cd adapters/outbox/mysql && GOWORK=off $(GO) build ./...
cd examples/http-service && GOWORK=off $(GO) build -o ../../bin/orbit-http-example ./cmd/server cd examples/http-service && GOWORK=off $(GO) build -o ../../bin/orbit-http-example ./cmd/server
$(GO) build -o bin/orbit ./cmd/orbit $(GO) build -o bin/orbit ./cmd/orbit
@@ -40,6 +44,12 @@ image:
integration: integration:
./scripts/test-mysql.sh ./scripts/test-mysql.sh
console-check:
node --check internal/transport/httpserver/console/console-select.js
node --check internal/transport/httpserver/console/app.js
node --check internal/transport/httpserver/console/applications.js
node --test scripts/test-console-state.cjs
console-e2e: console-e2e:
./scripts/test-console-e2e.sh ./scripts/test-console-e2e.sh

316
README.md
View File

@@ -1,122 +1,284 @@
# Orbit · 星轨 # Orbit · 星轨
Orbit 是面向多个业务项目的通用任务调度与流程编排平台,采用 **Go + MySQL + HTTP/WebSocket**。 **Go + MySQL 构建的任务调度与流程编排平台。** 业务应用通过 HTTP 提交任务,Worker 通过 WebSocket 执行,结果通过可靠订阅交付;任务状态、计划、流程检查点与审计保存在 MySQL。
- **Pulse · 脉动**:异步任务、定时调度、执行授权与安全重试。 - **Pulse · 脉动**:异步任务、延迟执行、定时计划、执行授权、重试与结果订阅。
- **Weave · 织流**:研发定义发布流程,管理步骤、等待、有界查询与恢复。 - **Weave · 织流**:研发定义并发布流程,支持顺序、并行、条件分支、等待信号、有界查询和人工恢复。
- 业务处理器运行在接入方 Worker 中;平台不内置行业规则。 - **Console**:账号密码登录的管理工作台,按应用与环境查看运行快照;支持任务/流程筛选、资源分页、ID 定位、审计与接入配置复制;具备连续错误临时锁定、账号/IP 限流及登录审计。[控制台使用说明](docs/console.md) · [登录保护配置](docs/console-login-security.md)。
## 当前进度 主分支:`main`。当前版本:**`v0.1.2`**。源码、SDK 和 Outbox 适配包采用固定版本发布,已发布标签不覆盖。变更见 [CHANGELOG](CHANGELOG.md)。
已完成 P0–P5 平台功能阶段验收:36 个数据模型、版本化迁移、凭据及范围校验、队列与任务 API、WSS 执行、独立 SDK、自动 Worker 和 [执行尝试/证据查询](docs/api/execution-history.md)。[Worker Schema](docs/api/worker-schema.md) 与真实进程强杀恢复回归已通过;[安全重试](docs/api/retries.md)、[定时计划](docs/api/schedules.md)、[运行中取消](docs/api/cancellation.md) 、[队列资源控制](docs/api/queues.md) 、[应用共享配额](docs/api/application-resources.md) 、[资源键互斥](docs/api/keyed-concurrency.md) 和 [优先级/节点公平派发](docs/api/priority-and-fairness.md) 已接入服务端和 SDK,[可靠结果订阅](docs/api/subscriptions.md) 已实现持久化核心、HTTP/WSS、管理 SDK 与示例,[消费 SDK](docs/sdk/event-consumer.md) 和 [独立 MySQL Inbox 示例](docs/examples/result-inbox.md) 已实现;[批量任务受理](docs/api/batch-tasks.md) 已提供逐项幂等、失败分类与 SDK 示例;[人工核查与重试](docs/api/task-recovery.md) 已提供带证据的管理接口、关联新任务、审计查询及运行示例;[业务键与时间范围查询](docs/api/task-queries.md) 已提供过滤、分页与SDK场景;[任务来源查询](docs/api/task-source.md) 已提供人工重试父任务、计划触发记录与固定版本;[业务事务Outbox](docs/examples/task-outbox.md) 已提供独立业务库、稳定提交身份、发送恢复与CLI;[相对延迟执行](docs/examples/delayed-task.md)已提供数据库计时及原请求恢复;完整范围核对见[P3验收](docs/reports/phase-3.md),生产验证与首版交付按 [持续开发计划](docs/08-development-plan.md) 继续推进。 ## 从这里开始
Weave已提供[定义发布](docs/api/workflow-definitions.md)、[实例启动、步骤详情、暂停/继续/取消、信号和操作审计](docs/api/workflows.md),以及[六类人工核查恢复](docs/api/workflow-recovery.md)的HTTP与独立Go SDK。持久运行器支持顺序、分支、有限并行、TIMER、SIGNAL及有界POLL,恢复沿用原预算与截止。[并行作业与回执示例](docs/examples/workflow.md)提供完整调用链;[历史激活/轮次/信号及信号审计](docs/api/workflow-history.md)已接入;[实例筛选分页](docs/api/workflow-queries.md)已接入,[状态事件时间线](docs/api/workflow-events.md)已接入,独立[轮询](docs/examples/workflow-poll.md)与[恢复](docs/examples/workflow-recovery.md)示例已接入,已补[版本/暂停竞争/全停回归](docs/reports/phase-4-5-races.md),功能阶段证据见[P4/P5核对](docs/reports/phase-4-5.md),提交断线及派发未送达见[故障边界](docs/reports/phase-6-fault-boundaries.md);[任务流程来源](docs/api/task-source.md#5-流程固定来源)已接入,P4/P5功能阶段已通过,P6生产验证和P7发布交付继续推进。 | 你要做什么 | 入口 |
| --- | --- |
| 第一次启动平台、设置管理员 | [快速开始](#快速开始) |
| 使用 Docker 启动,后续接入域名 | [Docker 与域名部署](#docker-与域名部署) |
| 了解全部能力和用法 | [功能一览](#功能一览) |
| 业务 Go 项目接入 | [SDK 怎么调用](#sdk-怎么调用) |
| 直接运行完整场景 | [examples:28 个可运行示例](examples/README.md) |
| 嵌入现有 HTTP 服务 | [HTTP + Outbox + Worker + Inbox](examples/http-service/README.md) |
| 查字段、错误码、权限及协议 | [HTTP / WebSocket API](docs/api/README.md)、[Go SDK 手册](docs/sdk/README.md) |
| 配置、排障、备份、发布 | [配置与运维](#配置与运维)、[运行手册](docs/20-operations-runbook.md) |
数据库禁止外键,关联一致性通过服务端事务校验,索引、唯一约束和 CHECK 保留;新装库使用无外键当前版本基线,已有库沿不可变迁移链升级;readiness 同时检查迁移及零外键要求。[运行观测](docs/api/observability.md)提供固定基数 HTTP、数据库池和后台批次指标;发布前可执行只读的 [`orbit-admin verify`](docs/api/operations.md) 核验迁移、零外键和固定索引。这不表示完整平台已具备生产服务能力。验证证据见 [P0](docs/reports/phase-0.md)、[P1](docs/reports/phase-1.md)、[P2 阶段验收](docs/reports/phase-2.md)、[安全重试](docs/reports/phase-3-safe-retry.md)、[计划调度](docs/reports/phase-3-schedules.md)、[取消与无外键回归](docs/reports/phase-3-cancellation.md) 及 [队列资源回归](docs/reports/phase-3-queue-resources.md)。 ## 功能一览
## 目录 每个示例目录都有 README、源码、启动方式和结果核对。接口手册包含字段、权限、错误码和恢复约定。
```text ### Pulse:任务与调度
cmd/orbit/ 基础 HTTP 服务入口
cmd/orbit-migrate/ 独立数据库迁移命令
cmd/orbit-admin/ 受控初始化与私密凭据交付
model/ 公共 ID、JSON、摘要与记录原语
platform/model/ 应用、命名空间、幂等、事件和审计
platform/auth/ 凭据格式与动作/队列授权范围
pulse/model/ 任务、尝试、队列、计划和执行许可
pulse/service/ 任务与队列应用契约、输入校验
pulse/worker/ 会话、开始、续租、结果和恢复契约
pulse/retry/ 冻结策略、有限退避与未知效果决策
pulse/schedule/ Cron/间隔、漏跑、版本及计划接口
internal/timezone/ 随计划冻结的内置时区数据快照
weave/model/ 定义、实例、步骤、信号和查询轮次
weave/definition/ 有限结构/类型校验与定义发布契约
weave/engine/ 不可变规则的有限步骤决策与精确结果映射
weave/instance/ 实例受理、当前详情及操作审计契约
weave/signal/ 内部可靠信号受理/查询契约及显式激活身份
weave/control/ 内部版本化暂停/继续/取消契约
internal/config/ 配置校验
internal/storage/mysql/ 连接、事务、迁移及集成测试
internal/transport/httpserver/ HTTP 接入
sdk/go/ 独立 Go SDK module 与示例
adapters/outbox/mysql/ 可直接引用的业务事务 Outbox 独立模块
examples/http-service/ HTTP + Outbox + Worker + Inbox 完整服务示例
scripts/ 可复现的回归工具
docs/ 设计、接口、SDK、场景与验证报告
```
## 本地运行 | 功能 | 做什么 / 怎么用 | 可运行示例 / 接口 |
| --- | --- | --- |
| 即时任务与提交幂等 | `SubmitTask` 提交固定处理器版本与 JSON;重报复用原操作键,`GetTask` 查当前状态 | [tasks](examples/tasks/README.md) · [任务接口](docs/api/tasks.md) |
| 延迟任务 | `DelayMS` 从首次受理计时;`AvailableAt` 指定绝对时刻 | [delayed-task](examples/delayed-task/README.md) |
| 批量受理 | `SubmitTasks` 最多 32 项,逐项返回受理/拒绝/未知,按原身份补交 | [batch](examples/batch/README.md) · [批量接口](docs/api/batch-tasks.md) |
| 自动 Worker | 注册处理器与版本,`NewWorker(...).Run(ctx)` 负责连接、授权、续租、上报与排空 | [worker](examples/worker/README.md) · [运行器手册](docs/sdk/worker-runtime.md) |
| 安全重试 | 冻结次数、退避与总时限;明确可重试失败自动再执行,未知效果按安全策略核查 | [retry](examples/retry/README.md) · [重试策略](docs/api/retries.md) |
| 取消 | `CancelTask` 保存取消意图;运行中的处理器配合停止并结清 | [cancellation](examples/cancellation/README.md) |
| 定时计划 | Cron / 固定间隔、时区、不可变版本、漏跑策略、暂停/恢复和触发历史 | [schedules](examples/schedules/README.md) · [计划接口](docs/api/schedules.md) |
| 资源退役 | 结清后退役订阅与队列,释放订阅名额,保留历史和审计 | [运行示例](sdk/go/examples/resource-lifecycle/README.md) · [接口与规则](docs/api/resource-retirement.md) |
| 队列资源控制 | 创建/配置队列并发、开始速率、积压上限和暂停;满额返回背压 | [resources](examples/resources/README.md) · [队列接口](docs/api/queues.md) |
| 应用共享配额 | 同一应用的多个命名空间/队列共享总额度 | [application-resources](examples/application-resources/README.md) |
| 资源键互斥 | `ConcurrencyKey` 协调跨队列同资源任务,资源端核验递增许可序号 | [keyed-concurrency](examples/keyed-concurrency/README.md) |
| 优先级 | 任务优先级 0–9,结合等待时间排序与节点轮转派发 | [priority](examples/priority/README.md) |
| 查询与来源 | 按队列、状态、业务键、创建时间分页;追溯普通提交、计划、流程和人工重试来源 | [task-query](examples/task-query/README.md) · [来源接口](docs/api/task-source.md) |
| 历史与证据 | 查询每次尝试、原结果及迟到/冲突报告,保留原始记录 | [history](examples/history/README.md) |
| 人工核查与重试 | `ReviewTask` 提交证据;`RetryTask` 创建关联新任务并保留审计 | [recovery](examples/recovery/README.md) |
要求 Go 1.27.1、MySQL 8.4+。先准备专用数据库和凭据,通过环境变量注入;程序不会自动读取 `.env` 文件。 ### Weave:流程编排
| 功能 | 做什么 / 怎么用 | 可运行示例 / 接口 |
| --- | --- | --- |
| 定义与版本 | 研发使用 SDK 创建定义、发布不可变版本;运行实例固定启动版本 | [workflow-definition](examples/workflow-definition/README.md) · [定义格式](docs/api/workflow-definition-format.md) |
| 顺序、条件、并行与汇合 | 用有限结构组合任务与结果映射;持久化每一步和推进检查点 | [workflow](examples/workflow/README.md) · [实例接口](docs/api/workflows.md) |
| 时间与外部信号等待 | TIMER 到期继续;SIGNAL 按固定等待身份接收外部回执 | [workflow](examples/workflow/README.md) · [信号设计](docs/14-workflow-signals.md) |
| 有界重复查询 | POLL 分别限制业务查询轮次和单轮请求重试,处理中继续等待,耗尽转核查 | [workflow-poll](examples/workflow-poll/README.md) |
| 暂停、继续、取消 | 停止推进后续工作,同时收集已发出的在途结果 | [控制接口](docs/api/workflows.md) · [控制语义](docs/15-workflow-controls.md) |
| 人工恢复 | 按原因、证据、版本核查任务/步骤/等待;恢复沿用原历史、预算和截止 | [workflow-recovery](examples/workflow-recovery/README.md) · [恢复接口](docs/api/workflow-recovery.md) |
| 实例查询与审计 | 筛选分页,查步骤详情、历史激活、查询轮次、信号及状态时间线 | [workflow-query](examples/workflow-query/README.md) · [历史接口](docs/api/workflow-history.md) · [时间线](docs/api/workflow-events.md) |
### 业务接入与管理
| 功能 | 做什么 / 怎么用 | 入口 |
| --- | --- | --- |
| 可靠结果订阅 | 先创建订阅,再由 EventConsumer 通过 WebSocket 接收结果;业务提交后 ACK,失败按预算重新交付 | [subscriptions](examples/subscriptions/README.md) · [消费 SDK](docs/sdk/event-consumer.md) |
| 事务 Outbox 公共包 | `EnqueueTx` 将待发请求写入业务事务,`Run` 后台发送;网络结果不明复用原身份 | [MySQL 适配包](docs/sdk/outbox-mysql.md) · [task-outbox](examples/task-outbox/README.md) |
| 业务结果 Inbox | 事件去重与业务更新同事务,提交成功后确认交付 | [result-inbox](examples/result-inbox/README.md) |
| HTTP 服务完整生命周期 | 业务接口、Outbox、Worker、结果消费、就绪检查和有界关闭放进同一业务服务 | [http-service](examples/http-service/README.md) |
| 平台身份与凭据 | 应用/命名空间/队列授权范围、凭据轮换/撤销;SDK 不直连平台数据库 | [鉴权](docs/api/authentication.md) · [凭据管理](docs/api/authentication.md) |
| 账号密码控制台 | 初始化管理员,按应用/环境/队列查看任务、计划、流程、交付与归档,列表和详情显示应用归属 | [Console 手册](docs/console.md) · [应用范围](docs/api/console-scope.md) |
| 保留策略与周期归档 | 配置各类数据保留天数,持久化归档计划/作业,分页、续跑、重试与文件核验 | [保留策略](docs/api/retention.md) · [周期归档](docs/api/archive-scheduler.md) |
| 运维与观测 | 健康/readiness、独立指标端口、迁移核验、负载工具、备份恢复与故障演练 | [观测](docs/api/observability.md) · [运维](docs/20-operations-runbook.md) |
## 快速开始
需要 **Go 1.27.1、MySQL 8.4**,先创建专用数据库 `orbit`;下方管理员密码提示和读取队列 ID 的辅助命令使用 Python 3。程序通过环境变量配置,**不会自动读取 `.env`**。如当前 shell 设置了 `GOTOOLCHAIN=local`,必须安装满足版本要求的 Go。
### 1. 获取代码并迁移数据库
```sh ```sh
git clone --branch v0.1.2 https://git.yuntuo.hk/k2safe/orbit.git
cd orbit
export ORBIT_MYSQL_DSN='user:password@tcp(127.0.0.1:3306)/orbit' export ORBIT_MYSQL_DSN='user:password@tcp(127.0.0.1:3306)/orbit'
export ORBIT_HTTP_ADDR='127.0.0.1:8080' export ORBIT_HTTP_ADDR='127.0.0.1:8080'
go run ./cmd/orbit-migrate up go run ./cmd/orbit-migrate up
```
DSN 替换为实际账号密码。`--branch v0.1.2` 检出固定发布版本;参与开发使用 `git switch main`。已有库先备份,再按[升级与发布手册](docs/20-operations-runbook.md)停旧写节点、迁移和核验;不修改已应用的迁移文件。
### 2. 一次性创建示例资源与管理员
下面在独立演示应用中授予所有流程及任务演示所需权限,并设置一个管理员。密码至少 12 字节,通过标准输入传递,不写入命令行或 Git。
```sh
umask 077
mkdir -p .local
python3 -c 'import getpass; print(getpass.getpass("设置管理员密码(至少12字节):"))' | \
go run ./cmd/orbit-admin bootstrap \
--application sample-app --namespace default --environment development \
--queue examples --worker-access --schedule-access --event-access \
--recovery-access --workflow-access --workflow-run-access \
--workflow-control-access --workflow-signal-access \
--workflow-recovery-access --workflow-audit-access \
--console-username admin --console-display-name 'Orbit 管理员' \
--console-password-stdin --output .local/development.credentials.json
```
管理员可在「应用接入」页面新建应用和初始队列、查看和调整有效期、平滑换证(默认长期 Token,换证时新旧共存 7 天),随时查看、复制包含当前 Token 的完整接入配置,或下载 orbit.env。设置 `ORBIT_CONSOLE_APPLICATION_ADMIN=admin` 指定唯一接入管理员,并通过 `ORBIT_CREDENTIAL_KEY_FILE` 配置 Token 加密保管密钥;本地 Compose 自动生成并持久保存。[应用接入使用与接口文档](docs/api/console-applications.md)。
初始化只运行一次,后续重启复用数据库、账号和 SDK 凭据。凭据 JSON 是服务端程序访问 API 的秘密文件,**控制台不需要选择或上传它**。已有资源增加管理员的方法见 [Console 手册](docs/console.md);真实接入按实际角色缩小权限。
### 3. 启动平台,进入控制台
```sh
export ORBIT_CONSOLE_QUEUE_ID="$(python3 -c 'import json; print(json.load(open(".local/development.credentials.json"))["queue_id"])')"
go run ./cmd/orbit go run ./cmd/orbit
``` ```
上方 DSN 为本地占位示例,需替换为实际凭据。部署时使用秘密管理和经过验证的 TLS 配置;迁移账户与运行账户分开授权。运行程序不自动迁移数据库。 打开 **<http://127.0.0.1:8080/console/>**,用 `admin` 和刚设置的密码登录。页面自动使用当前访问地址请求服务端,统计与列表从平台接口读取 MySQL 中的数据。
另一个终端执行 SDK 示例: ### 4. 跑一条完整执行链
另开终端,从仓库根目录执行:
```sh ```sh
cd sdk/go export ORBIT_URL=http://127.0.0.1:8080
ORBIT_URL=http://127.0.0.1:8080 go run ./examples/health export ORBIT_CREDENTIALS_FILE="$PWD/.local/development.credentials.json"
cd examples
go run ./health
go run ./worker
``` ```
任务接入从 [初始化凭据](docs/api/authentication.md) 开始,再按 [SDK 接入](docs/sdk/README.md) 运行受理/取消示例。[自动 Worker 示例](docs/sdk/worker-runtime.md) 演示处理器注册、并发消费、结果确认与排空;特殊接入也可使用 [底层协议示例](docs/sdk/worker.md)。 健康检查显示 `liveness=alive readiness=ready`;Worker 示例实际创建并执行三条文本任务,最后输出:
## 开发与回归 ```text
task=<任务ID> state=SUCCEEDED result={"text":"HELLO ORBIT"}
task=<任务ID> state=SUCCEEDED result={"text":"REUSABLE WORKER"}
task=<任务ID> state=SUCCEEDED result={"text":"DURABLE RESULT"}
worker_drained=true started=3 confirmed=3 running=0
```
刷新控制台可查看这些任务。继续在 `examples` 目录运行 `go run ./schedules`、`go run ./workflow` 或 `go run ./workflow-poll` 体验定时和流程;全部 27 个场景及特殊准备条件见 [examples/README.md](examples/README.md)。
## SDK 怎么调用
### 安装固定版本
在自己的业务项目中执行:
```sh ```sh
make fmt go get git.yuntuo.hk/k2safe/orbit/sdk/go@v0.1.2
make test # 业务事务需要 MySQL Outbox 时再安装:
make vet go get git.yuntuo.hk/k2safe/orbit/adapters/outbox/mysql@v0.1.1
make build
make image
make integration
make console-e2e
make protocol-check
make docs-check
``` ```
首版发布前按[交付核对清单](docs/release-checklist.md)逐项留存命令输出和目标环境证据;当前阶段回归不替代生产拓扑、容量、复制切换或 RPO/RTO 验收。 无需本地源码或 `replace`。SDK 是独立 Go module,只依赖标准库和 WebSocket 客户端;MySQL 驱动属于可选适配包。子模块的 Git 标签分别为 `sdk/go/v0.1.2` 和 `adapters/outbox/mysql/v0.1.1`。
`make integration` 要求 Docker、OpenSSL 等标准命令,启动独立的临时 MySQL 容器,使用随机凭据和回环随机端口;完成后删除该测试容器。不会连接已有业务数据库。可通过 `GO`、`DOCKER` 和 `ORBIT_TEST_MYSQL_IMAGE` 指定工具/测试镜像。 ### 提交、执行、接收结果
受理层负载采样工具见 [有界受理负载工具](docs/api/load.md),只允许在隔离命名空间或一次性数据库中运行;它不自动重试、不启动 Worker,也不提供生产容量承诺。 一次完整接入分为三个角色,可以分进程,也可以嵌入同一业务 HTTP 服务:
历史数据可通过控制台配置保留窗口,也可使用 [`orbit-admin retention archive`](docs/api/retention-jobs.md) 自动分批落盘、断点续跑和离线核验。当前保留源数据,周期归档调度和删除执行器另行交付。 ```text
业务事务 → Outbox → HTTP 提交到 Orbit → WebSocket Worker 执行业务
↓
业务数据 ← Inbox ← WebSocket 结果订阅 ← 持久化结果
```
真实Worker与任务完成路径测量使用[`orbit-exec-load`](docs/api/execution-load.md):短/混合/中长模拟任务、持久结果和单次尝试核验、阶段延迟分布;不修改队列额度、不调用外部业务系统。定时积压复现可运行 `make schedule-backlog`,它只使用一次性 MySQL,并保留有界截止负例的实际分母。Weave 并行流程链路使用[`orbit-workflow-load`](docs/api/workflow-load.md),核对固定版本、步骤、来源和最终输出。定时集中触发使用[`orbit-schedule-load`](docs/api/schedule-load.md),逐项核对触发、任务、唯一尝试与来源,并保留超时分母和暂停收尾证据。 下面是业务函数中的提交片段;完整 imports、main、Worker 注册和收尾见 [worker/main.go](examples/worker/main.go)。`baseURL` 为实际平台地址,例如 `https://orbit.example.com`;`token` 和 `queueID` 从业务配置/Secret 注入。
SDK 独立发布门禁使用 `make sdk-check`,在 `GOWORK=off` 下检查完整依赖图,并运行 SDK 的竞态测试、vet 和全包构建;规则和接入边界见 [SDK 发布门禁](docs/sdk/release.md)。 ```go
client, err := orbit.NewClient(baseURL, orbit.Options{Token: token})
if err != nil { return err }
修改已应用迁移时会触发校验和拒绝;新增结构使用新的前向迁移。初始结构尚未部署生产。 // operationKey 和完整 request 必须先保存在业务库;网络重报仍使用原值。
request := orbit.SubmitTaskRequest{
QueueID: queueID,
Handler: "object.prepare", HandlerVersion: "v1", PayloadVersion: "v1",
Payload: json.RawMessage(`{"object_ref":"objects/input"}`),
TaskTimeoutMS: 60000,
Retry: orbit.RetryPolicy{MaxAttempts: 1, AttemptTimeoutMS: 10000},
RecoverySafety: orbit.RecoveryReconcileOnly,
}
accepted, err := client.SubmitTask(ctx, operationKey, request)
if err != nil { return err }
current, err := client.GetTask(ctx, accepted.Task.ID)
if err != nil { return err }
fmt.Println(current.ID, current.State)
```
## 文档入口 导入路径为 `orbit "git.yuntuo.hk/k2safe/orbit/sdk/go"`。处理器的名称、处理器版本和载荷版本必须与 Worker 注册能力一致;没有匹配的在线 Worker 时,提交成功也不会立即执行。
- [持续开发与回归计划](docs/08-development-plan.md) **任务受理不等于执行成功。** 同键重报返回原回执,最新状态用 `GetTask` 或结果事件核对。平台不能替外部系统保证“恰好执行一次”;副作用须使用业务幂等键、事务或证据核查。
- [数据模型与约束](docs/07-data-model.md)
- [HTTP / WebSocket 接口手册](docs/api/README.md)
- [Go SDK 接入](docs/sdk/README.md)
- [通用场景示例](docs/examples/README.md)
- [Orbit Console 控制台](docs/console.md)
- [运行与发布手册](docs/20-operations-runbook.md)
- [容器发布说明](docs/21-container-deployment.md)
- [设计文档总览](docs/README.md)
Git 远端:[k2safe/orbit](https://git.yuntuo.hk/k2safe/orbit),主分支 `main`。首个接入版本为 `v0.1.0`,业务项目使用 Go 1.27.1 或更高版本安装: 结果通知使用 `NewEventConsumer(...).Run(ctx)`。先创建持久订阅,再提交希望接收的任务;消费函数在 Inbox 与业务变更明确提交后返回 nil,SDK 才 ACK。断线重连、重复交付和业务去重见[消费手册](docs/sdk/event-consumer.md)。
### 现有 HTTP 服务如何接入
直接从 [examples/http-service](examples/http-service/README.md) 开始,完整命令、配置及 curl 请求见[运行手册](docs/examples/http-service.md)。该工程提供:
1. `init`:在独立业务库创建 Outbox、业务表、Inbox 和结果视图。
2. `provision`:创建可靠结果订阅,将订阅 ID 保存到部署配置。
3. `serve`:启动业务 HTTP、Outbox 发送器、Worker 和结果消费者。
4. 业务请求返回本地受理状态;随后查询到平台 TaskID、执行结果和业务视图。
5. 收到退出信号后,依次收尾 HTTP、发送器/Worker、结果消费者,最后关闭数据库。
只抽取发送器时使用[公共 Outbox 包](adapters/outbox/mysql/README.md):`EnqueueTx` 加入调用方事务,不提交事务、不发网络请求;`Run` 在后台提交并核对平台回执。业务确认钩子与 Outbox 确认同事务执行。
## Docker 与域名部署
本机给其他服务联调,可直接运行 `./scripts/orbit-local.py up`,自动部署到 `18080`,生成管理员和 SDK 配置;完整地址、Docker 网络与启停方法见[本地 Compose 测试环境](deploy/local/README.md)。
仓库提供 [Dockerfile](Dockerfile)、[Compose 启动链](deploy/docker-compose.yml)和 [Nginx 配置](deploy/nginx/orbit.conf.example)。按[完整 Compose 手册](docs/22-compose-deployment.md)注入数据库密码、构建镜像、启动 MySQL/迁移/核验、初始化管理员,最后启动 Orbit。手册也包括停止、更新与两节点覆盖配置。
- Console 同源访问:域名反向代理到 Orbit 后,页面自动使用这个域名,无需在界面填写服务地址。
- 业务 SDK:把自己的 `baseURL` / 示例 `ORBIT_URL` 配置为该 HTTPS 域名,SDK 使用相应 WSS 地址。
- 网关保留 WebSocket Upgrade/Connection 头,健康检查使用 `/health/ready`。
- 停止容器保留 MySQL 和归档持久卷;更换镜像不等于删除数据。
## 配置与运维
配置完整示例见 [.env.example](.env.example)。由 shell、部署平台或 Secret 管理器显式注入:
| 配置 | 用途 |
| --- | --- |
| `ORBIT_MYSQL_DSN` | 平台数据库连接,迁移账号与运行账号按部署手册分开 |
| `ORBIT_HTTP_ADDR` | 服务进程监听地址,例 `127.0.0.1:8080` |
| `ORBIT_CONSOLE_QUEUE_ID` | 控制台默认队列;不授予账号额外权限 |
| `ORBIT_CONSOLE_APPLICATION_ADMIN` | 指定唯一可接入和管理各应用的控制台登录名;空值不开放跨应用权限,多节点保持一致 |
| `ORBIT_DB_MAX_OPEN` / `ORBIT_DB_MAX_IDLE` | 数据库连接池上限 |
| `ORBIT_SHUTDOWN_TIMEOUT` | SIGTERM 关闭窗口,默认 10s |
| `ORBIT_WORKFLOW_TICK_INTERVAL` / `ORBIT_SCHEDULE_TICK_INTERVAL` | 流程/计划后台扫描间隔,默认 1s |
| `ORBIT_RECOVERY_TICK_INTERVAL` / `ORBIT_RUNTIME_BATCH_LIMIT` | 恢复扫描间隔与每批上限,默认 2s / 100 |
| `ORBIT_WORKER_CONNECTION_LIMIT` / `ORBIT_EVENT_CONNECTION_LIMIT` | 每节点 WS 连接上限,默认各 128 |
| `ORBIT_DISPATCH_WORKERS` / `ORBIT_DISPATCH_CAPACITY` | 派发并发和有界内存队列,默认 4 / 128 |
| `ORBIT_METRICS_ADDR` | 独立内部指标监听,默认关闭 |
| `ORBIT_RETENTION_*_DAYS` | 首次初始化保留窗口;控制台保存后以数据库策略为准 |
| `ORBIT_ARCHIVE_ROOT` / `ORBIT_ARCHIVE_STORAGE_ID` | 周期归档卷路径与固定卷身份,二者一起配置 |
| `ORBIT_ARCHIVE_MAX_BYTES` / `ORBIT_ARCHIVE_TICK_INTERVAL` | 归档卷预算和调度间隔,默认 10 GiB / 10s |
默认保留窗口:任务、流程、事件各 **365 天**,交付、Inbox、幂等记录各 **90 天**,审计 **2555 天**。控制台可修改策略并配置周期归档;未结清任务、未知效果、未确认交付等受保护记录不会按时间简单处理。**当前归档导出并保留源数据,尚未提供源数据自动删除执行器。** 详细规则见[保留策略](docs/api/retention.md)和[归档作业](docs/api/archive-scheduler.md)。
常用检查:
```sh ```sh
go get git.yuntuo.hk/k2safe/orbit/sdk/go@v0.1.0 curl --fail http://127.0.0.1:8080/health/ready
go run ./cmd/orbit-admin verify
go run ./cmd/orbit-admin observe snapshot
``` ```
无需本地 `replace`;导入方式、完整调用与版本边界见 [SDK 接入](docs/sdk/README.md#5-外部项目通过远端接入)。 数据库禁止外键和级联删除;关联一致性由事务校验,保留唯一约束、索引和 CHECK。持久化模型及 SQL 字段都有中文注释。已有迁移不可回改,演进采用前向迁移。
[流程实例筛选分页](docs/api/workflow-queries.md)已提供独立SDK和[完整示例](docs/examples/workflow-query.md),按固定版本全部队列鉴权,数据库保持零外键。 ## 项目目录
- [周期归档与作业管理](docs/api/archive-scheduler.md) ```text
cmd/ 平台、数据库迁移和管理命令
platform/ 应用、身份、授权、幂等、事件、审计
pulse/ 任务、Worker、重试、队列、定时计划
weave/ 流程定义、实例、步骤、等待和恢复
model/ 公共持久化类型与校验
internal/ MySQL 存储、HTTP/WS、配置与观测
sdk/go/ 可独立引用的 Go SDK
adapters/outbox/mysql/ 可独立引用的 MySQL Outbox 包
examples/ 27 个可运行场景及各自 README
deploy/ Compose、Nginx 和部署配置
scripts/ 构建、回归、故障和发布核验
docs/ API、SDK、场景、设计及验收报告
```
业务接入可直接使用[MySQL 事务 Outbox 适配包](docs/sdk/outbox-mysql.md)和[完整 HTTP 生命周期示例](docs/examples/http-service.md),覆盖已有事务、后台发送、结果入库以及有界关闭。 ## 测试、版本与边界
在仓库根目录执行:
```sh
make test vet build # 7 个模块的竞态测试、静态检查与构建
make sdk-check protocol-check docs-check
make integration # 临时 MySQL、真实平台、示例及故障回归
make console-check # 前端查询状态回归(开发机需 Node.js)
make console-e2e # 控制台端到端回归
```
集成测试需要 Docker、Python 3 和 OpenSSL 等工具,由脚本创建独立临时数据库并清理自建容器。生产容量与故障域验收另见[交付清单](docs/release-checklist.md);有限样本不能代表百万企业规模的生产容量。
`v0.1.2` 新增通用资源退役;此前已包含账号密码控制台、归档策略/周期作业、Outbox 公共包、HTTP 生命周期示例及统一示例目录;与上一版本的升级说明和验证结果见 [CHANGELOG](CHANGELOG.md) 与 [本次验证](docs/reports/resource-retirement.md)。当前未提供源数据删除、其他数据库 Outbox 适配,也不把单机或隔离环境多节点测试等同于生产跨故障域高可用验收。
更多资料:[设计文档](docs/README.md) · [持续开发计划](docs/08-development-plan.md) · [接口目录](docs/api/README.md) · [示例目录](examples/README.md) · [发布规则](docs/sdk/release.md)。

View File

@@ -8,3 +8,15 @@
- [测试报告](../../../docs/reports/outbox-http-integration.md) - [测试报告](../../../docs/reports/outbox-http-integration.md)
以业务自己的数据库存储待发命令,调用 `EnqueueTx` 加入已有事务,后台运行 `Run` 或 `SendOnce`。本包确认的是平台受理,任务执行完成通过 Worker 和可靠结果订阅衔接。 以业务自己的数据库存储待发命令,调用 `EnqueueTx` 加入已有事务,后台运行 `Run` 或 `SendOnce`。本包确认的是平台受理,任务执行完成通过 Worker 和可靠结果订阅衔接。
## 安装
```sh
go get git.yuntuo.hk/k2safe/orbit/adapters/outbox/mysql@v0.1.1
```
```go
import outbox "git.yuntuo.hk/k2safe/orbit/adapters/outbox/mysql"
```
Git 标签为 `adapters/outbox/mysql/v0.1.1`,无需本地 replace。先将 `SchemaSQL()` 纳入自己的业务迁移,再构造 `Store`;完整事务和运行器代码见上方接口手册。

View File

@@ -13,25 +13,30 @@ import (
"time" "time"
"git.yuntuo.hk/k2safe/orbit/internal/config" "git.yuntuo.hk/k2safe/orbit/internal/config"
"git.yuntuo.hk/k2safe/orbit/internal/credentialvault"
"git.yuntuo.hk/k2safe/orbit/internal/storage/mysql" "git.yuntuo.hk/k2safe/orbit/internal/storage/mysql"
core "git.yuntuo.hk/k2safe/orbit/model" core "git.yuntuo.hk/k2safe/orbit/model"
) )
func runCredential(args []string) error { func runCredential(args []string) error {
if len(args) == 0 { if len(args) == 0 {
return errors.New("usage: orbit-admin credential status|rotate|revoke|apply") return errors.New("usage: orbit-admin credential status|rotate|expiry|finalize|revoke|apply")
} }
switch args[0] { switch args[0] {
case "status": case "status":
return runCredentialStatus(args[1:]) return runCredentialStatus(args[1:])
case "rotate": case "rotate":
return runCredentialChange(args[1:], "ROTATE") return runCredentialChange(args[1:], "ROTATE")
case "expiry":
return runCredentialChange(args[1:], "SET_EXPIRY")
case "finalize":
return runCredentialChange(args[1:], "FINALIZE")
case "revoke": case "revoke":
return runCredentialChange(args[1:], "REVOKE") return runCredentialChange(args[1:], "REVOKE")
case "apply": case "apply":
return runCredentialApply(args[1:]) return runCredentialApply(args[1:])
default: default:
return errors.New("usage: orbit-admin credential status|rotate|revoke|apply") return errors.New("usage: orbit-admin credential status|rotate|expiry|finalize|revoke|apply")
} }
} }
@@ -64,14 +69,19 @@ func runCredentialStatus(args []string) error {
func runCredentialChange(args []string, action string) error { func runCredentialChange(args []string, action string) error {
flags := flag.NewFlagSet("credential "+strings.ToLower(action), flag.ContinueOnError) flags := flag.NewFlagSet("credential "+strings.ToLower(action), flag.ContinueOnError)
namespace, credential, output, reason, validFor := "", "", "", "", "720h" namespace, credential, output, reason, validFor := "", "", "", "", "0"
grace := time.Duration(0)
if action == "ROTATE" {
grace = 7 * 24 * time.Hour
}
var expected uint64 var expected uint64
flags.StringVar(&namespace, "namespace-id", "", "credential namespace id") flags.StringVar(&namespace, "namespace-id", "", "credential namespace id")
flags.StringVar(&credential, "credential-id", "", "credential id") flags.StringVar(&credential, "credential-id", "", "credential id")
flags.Uint64Var(&expected, "expected-revision", 0, "current credential revision required for first apply") flags.Uint64Var(&expected, "expected-revision", 0, "current credential revision required for first apply")
flags.StringVar(&reason, "reason", "", "required audit reason") flags.StringVar(&reason, "reason", "", "required audit reason")
flags.StringVar(&output, "output", "", "new private operation file; an existing file is never overwritten") flags.StringVar(&output, "output", "", "new private operation file; an existing file is never overwritten")
flags.StringVar(&validFor, "valid-for", "720h", "new credential validity, from 1h to 8760h") flags.StringVar(&validFor, "valid-for", "0", "credential validity: 0 permanent, or 1h to 8760h")
flags.DurationVar(&grace, "grace", grace, "rotation overlap: 0 immediate, up to 720h; default 168h")
if err := flags.Parse(args); err != nil { if err := flags.Parse(args); err != nil {
return err return err
} }
@@ -83,7 +93,7 @@ func runCredentialChange(args []string, action string) error {
return errors.New("credential change requires valid ids and a nonzero --expected-revision") return errors.New("credential change requires valid ids and a nonzero --expected-revision")
} }
duration := time.Duration(0) duration := time.Duration(0)
if action == "ROTATE" { if action == "ROTATE" || action == "SET_EXPIRY" {
duration, err = time.ParseDuration(validFor) duration, err = time.ParseDuration(validFor)
if err != nil { if err != nil {
return errors.New("invalid --valid-for duration") return errors.New("invalid --valid-for duration")
@@ -95,7 +105,7 @@ func runCredentialChange(args []string, action string) error {
} }
defer closeDB() defer closeDB()
op, err := mysql.PrepareCredentialOperation(ctx, db, mysql.CredentialChangeInput{ op, err := mysql.PrepareCredentialOperation(ctx, db, mysql.CredentialChangeInput{
NamespaceID: ns, CredentialID: id, ExpectedRevision: expected, Action: action, ValidFor: duration, Reason: reason, NamespaceID: ns, CredentialID: id, ExpectedRevision: expected, Action: action, ValidFor: duration, GraceFor: grace, Reason: reason,
}) })
if err != nil { if err != nil {
return errors.New("credential operation could not be prepared") return errors.New("credential operation could not be prepared")
@@ -103,7 +113,11 @@ func runCredentialChange(args []string, action string) error {
if err := writePrivateOperation(output, op); err != nil { if err := writePrivateOperation(output, op); err != nil {
return err return err
} }
receipt, err := mysql.ApplyCredentialOperation(ctx, db, op) vault, err := credentialvault.LoadFile(os.Getenv("ORBIT_CREDENTIAL_KEY_FILE"))
if err != nil {
return err
}
receipt, err := mysql.ApplyCredentialOperation(ctx, db, op, vault)
if err != nil { if err != nil {
return errors.New("credential operation was not confirmed; the private operation file was retained for reconciliation") return errors.New("credential operation was not confirmed; the private operation file was retained for reconciliation")
} }
@@ -129,7 +143,11 @@ func runCredentialApply(args []string) error {
return err return err
} }
defer closeDB() defer closeDB()
receipt, err := mysql.ApplyCredentialOperation(ctx, db, op) vault, err := credentialvault.LoadFile(os.Getenv("ORBIT_CREDENTIAL_KEY_FILE"))
if err != nil {
return err
}
receipt, err := mysql.ApplyCredentialOperation(ctx, db, op, vault)
if err != nil { if err != nil {
return errors.New("credential operation was not confirmed; retry with the same private operation file") return errors.New("credential operation was not confirmed; retry with the same private operation file")
} }

View File

@@ -15,6 +15,7 @@ import (
"git.yuntuo.hk/k2safe/orbit/internal/buildinfo" "git.yuntuo.hk/k2safe/orbit/internal/buildinfo"
"git.yuntuo.hk/k2safe/orbit/internal/config" "git.yuntuo.hk/k2safe/orbit/internal/config"
"git.yuntuo.hk/k2safe/orbit/internal/credentialvault"
"git.yuntuo.hk/k2safe/orbit/internal/storage/mysql" "git.yuntuo.hk/k2safe/orbit/internal/storage/mysql"
core "git.yuntuo.hk/k2safe/orbit/model" core "git.yuntuo.hk/k2safe/orbit/model"
) )
@@ -257,6 +258,7 @@ func runBootstrap(args []string) error {
var in mysql.BootstrapInput var in mysql.BootstrapInput
var output string var output string
flags.StringVar(&in.Application, "application", "", "new application name") flags.StringVar(&in.Application, "application", "", "new application name")
flags.DurationVar(&in.ValidFor, "valid-for", 0, "initial credential validity: 0 permanent, or 1h to 8760h")
flags.Func("application-id", "existing application id; mutually exclusive with --application", func(v string) error { flags.Func("application-id", "existing application id; mutually exclusive with --application", func(v string) error {
in.ExistingApplicationID = core.ID(v) in.ExistingApplicationID = core.ID(v)
return in.ExistingApplicationID.Validate() return in.ExistingApplicationID.Validate()
@@ -305,6 +307,10 @@ func runBootstrap(args []string) error {
if err != nil { if err != nil {
return err return err
} }
vault, err := credentialvault.LoadFile(cfg.CredentialKeyFile)
if err != nil {
return err
}
file, err := os.OpenFile(output, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0600) file, err := os.OpenFile(output, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0600)
if err != nil { if err != nil {
return errors.New("cannot create new private output file (existing files are never overwritten)") return errors.New("cannot create new private output file (existing files are never overwritten)")
@@ -344,14 +350,14 @@ func runBootstrap(args []string) error {
} }
delivered = true delivered = true
return nil return nil
}) }, vault)
if err != nil { if err != nil {
if delivered { if delivered {
return errors.New("bootstrap commit could not be confirmed; private output was retained; verify its credential before retrying") return errors.New("bootstrap commit could not be confirmed; private output was retained; verify its credential before retrying")
} }
return errors.New("bootstrap failed before credential delivery; check schema, names and database access") return errors.New("bootstrap failed before credential delivery; check schema, names and database access")
} }
fmt.Println("Bootstrap committed. Credentials saved in the requested private file; valid for 30 days.") fmt.Println("Bootstrap committed. Credentials saved in the requested private file; expiry follows --valid-for (default: permanent).")
return nil return nil
} }

View File

@@ -12,6 +12,7 @@ import (
"time" "time"
"git.yuntuo.hk/k2safe/orbit/internal/config" "git.yuntuo.hk/k2safe/orbit/internal/config"
"git.yuntuo.hk/k2safe/orbit/internal/credentialvault"
"git.yuntuo.hk/k2safe/orbit/internal/observability" "git.yuntuo.hk/k2safe/orbit/internal/observability"
"git.yuntuo.hk/k2safe/orbit/internal/retention" "git.yuntuo.hk/k2safe/orbit/internal/retention"
"git.yuntuo.hk/k2safe/orbit/internal/storage/mysql" "git.yuntuo.hk/k2safe/orbit/internal/storage/mysql"
@@ -41,6 +42,13 @@ func run() error {
if err != nil { if err != nil {
return err return err
} }
vault, err := credentialvault.LoadFile(cfg.CredentialKeyFile)
if err != nil {
return err
}
if cfg.ConsoleApplicationAdmin != "" && vault == nil {
return errors.New("ORBIT_CREDENTIAL_KEY_FILE is required for console application administration")
}
root, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) root, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stop() defer stop()
startup, cancel := context.WithTimeout(root, 10*time.Second) startup, cancel := context.WithTimeout(root, 10*time.Second)
@@ -85,7 +93,29 @@ func run() error {
txStats := mysql.ReadTransactionStats() txStats := mysql.ReadTransactionStats()
metrics.RecordTransactionStats(observability.TransactionStats{Retries: txStats.Retries, Exhausted: txStats.Exhausted}) metrics.RecordTransactionStats(observability.TransactionStats{Retries: txStats.Retries, Exhausted: txStats.Exhausted})
} }
consoleAuth := mysql.NewConsoleAuthStore(db) consoleAuth := mysql.NewConsoleAuthStore(db, cfg.ConsoleLogin)
// 登录安全记录独立保留,每分钟有界清理,关闭时等待清理器退出。
loginCleanupCtx, stopLoginCleanup := context.WithCancel(root)
loginCleanupDone := make(chan struct{})
go func() {
defer close(loginCleanupDone)
ticker := time.NewTicker(time.Minute)
defer ticker.Stop()
for {
select {
case <-loginCleanupCtx.Done():
return
case <-ticker.C:
call, cancel := context.WithTimeout(loginCleanupCtx, 5*time.Second)
err := consoleAuth.CleanupLoginSecurity(call)
cancel()
if err != nil && loginCleanupCtx.Err() == nil {
slog.Error("console login security cleanup failed")
}
}
}
}()
defer func() { stopLoginCleanup(); <-loginCleanupDone }()
retentionStore := mysql.NewRetentionPolicyStore(db, cfg.RetentionDefaults) retentionStore := mysql.NewRetentionPolicyStore(db, cfg.RetentionDefaults)
server := httpserver.NewWithConsoleAuth(cfg.HTTPAddr, readiness.Check, consoleAuth, service.New(mysql.NewTaskStore(db))) server := httpserver.NewWithConsoleAuth(cfg.HTTPAddr, readiness.Check, consoleAuth, service.New(mysql.NewTaskStore(db)))
httpserver.RegisterApplicationResources(server, resources.New(mysql.NewTaskStore(db))) httpserver.RegisterApplicationResources(server, resources.New(mysql.NewTaskStore(db)))
@@ -125,7 +155,10 @@ func run() error {
httpserver.RegisterWorkflows(server, instance.New(mysql.NewWorkflowInstanceStore(db)), control.New(mysql.NewWorkflowControlStore(db)), weavesignal.New(mysql.NewWorkflowSignalStore(db)), recovery.New(mysql.NewWorkflowRecoveryStore(db))) httpserver.RegisterWorkflows(server, instance.New(mysql.NewWorkflowInstanceStore(db)), control.New(mysql.NewWorkflowControlStore(db)), weavesignal.New(mysql.NewWorkflowSignalStore(db)), recovery.New(mysql.NewWorkflowRecoveryStore(db)))
httpserver.RegisterConsoleRetention(server, consoleAuth, retentionStore, retentionStore) httpserver.RegisterConsoleRetention(server, consoleAuth, retentionStore, retentionStore)
httpserver.RegisterConsoleArchiveJobs(server, consoleAuth, retentionStore, cfg.ArchiveStorageID) httpserver.RegisterConsoleArchiveJobs(server, consoleAuth, retentionStore, cfg.ArchiveStorageID)
httpserver.WrapConsoleAuth(server, consoleAuth) consoleApplications := mysql.NewConsoleApplicationStore(db, cfg.ConsoleApplicationAdmin, vault)
httpserver.RegisterConsoleApplications(server, consoleAuth, consoleApplications)
httpserver.RegisterConsoleScopes(server, consoleApplications)
httpserver.WrapConsoleAuth(server, consoleAuth, consoleApplications)
httpserver.WrapMetrics(server, metrics) httpserver.WrapMetrics(server, metrics)
if cfg.ArchiveRoot != "" { if cfg.ArchiveRoot != "" {

View File

@@ -24,6 +24,15 @@ x-orbit-environment: &orbit-environment
ORBIT_RETENTION_INBOX_DAYS: ${ORBIT_RETENTION_INBOX_DAYS:-90} ORBIT_RETENTION_INBOX_DAYS: ${ORBIT_RETENTION_INBOX_DAYS:-90}
ORBIT_RETENTION_AUDIT_DAYS: ${ORBIT_RETENTION_AUDIT_DAYS:-2555} ORBIT_RETENTION_AUDIT_DAYS: ${ORBIT_RETENTION_AUDIT_DAYS:-2555}
ORBIT_CONSOLE_QUEUE_ID: ${ORBIT_CONSOLE_QUEUE_ID:-} ORBIT_CONSOLE_QUEUE_ID: ${ORBIT_CONSOLE_QUEUE_ID:-}
ORBIT_CONSOLE_APPLICATION_ADMIN: ${ORBIT_CONSOLE_APPLICATION_ADMIN:-}
ORBIT_CONSOLE_LOGIN_FAILURE_LIMIT: ${ORBIT_CONSOLE_LOGIN_FAILURE_LIMIT:-5}
ORBIT_CONSOLE_LOGIN_FAILURE_WINDOW: ${ORBIT_CONSOLE_LOGIN_FAILURE_WINDOW:-15m}
ORBIT_CONSOLE_LOGIN_LOCK_DURATION: ${ORBIT_CONSOLE_LOGIN_LOCK_DURATION:-15m}
ORBIT_CONSOLE_LOGIN_ACCOUNT_LIMIT: ${ORBIT_CONSOLE_LOGIN_ACCOUNT_LIMIT:-10}
ORBIT_CONSOLE_LOGIN_IP_LIMIT: ${ORBIT_CONSOLE_LOGIN_IP_LIMIT:-30}
ORBIT_CONSOLE_LOGIN_RATE_WINDOW: ${ORBIT_CONSOLE_LOGIN_RATE_WINDOW:-1m}
ORBIT_CONSOLE_LOGIN_AUDIT_DAYS: ${ORBIT_CONSOLE_LOGIN_AUDIT_DAYS:-90}
ORBIT_CONSOLE_TRUSTED_PROXIES: ${ORBIT_CONSOLE_TRUSTED_PROXIES:-}
ORBIT_METRICS_ADDR: ${ORBIT_METRICS_ADDR:-} ORBIT_METRICS_ADDR: ${ORBIT_METRICS_ADDR:-}
services: services:

View File

@@ -92,6 +92,16 @@ services:
ORBIT_RETENTION_DELIVERY_DAYS: ${ORBIT_RETENTION_DELIVERY_DAYS:-90} ORBIT_RETENTION_DELIVERY_DAYS: ${ORBIT_RETENTION_DELIVERY_DAYS:-90}
ORBIT_RETENTION_INBOX_DAYS: ${ORBIT_RETENTION_INBOX_DAYS:-90} ORBIT_RETENTION_INBOX_DAYS: ${ORBIT_RETENTION_INBOX_DAYS:-90}
ORBIT_RETENTION_AUDIT_DAYS: ${ORBIT_RETENTION_AUDIT_DAYS:-2555} ORBIT_RETENTION_AUDIT_DAYS: ${ORBIT_RETENTION_AUDIT_DAYS:-2555}
ORBIT_CONSOLE_APPLICATION_ADMIN: ${ORBIT_CONSOLE_APPLICATION_ADMIN:-}
ORBIT_CONSOLE_LOGIN_FAILURE_LIMIT: ${ORBIT_CONSOLE_LOGIN_FAILURE_LIMIT:-5}
ORBIT_CONSOLE_LOGIN_FAILURE_WINDOW: ${ORBIT_CONSOLE_LOGIN_FAILURE_WINDOW:-15m}
ORBIT_CONSOLE_LOGIN_LOCK_DURATION: ${ORBIT_CONSOLE_LOGIN_LOCK_DURATION:-15m}
ORBIT_CONSOLE_LOGIN_ACCOUNT_LIMIT: ${ORBIT_CONSOLE_LOGIN_ACCOUNT_LIMIT:-10}
ORBIT_CONSOLE_LOGIN_IP_LIMIT: ${ORBIT_CONSOLE_LOGIN_IP_LIMIT:-30}
ORBIT_CONSOLE_LOGIN_RATE_WINDOW: ${ORBIT_CONSOLE_LOGIN_RATE_WINDOW:-1m}
ORBIT_CONSOLE_LOGIN_AUDIT_DAYS: ${ORBIT_CONSOLE_LOGIN_AUDIT_DAYS:-90}
ORBIT_CONSOLE_TRUSTED_PROXIES: ${ORBIT_CONSOLE_TRUSTED_PROXIES:-}
ORBIT_CREDENTIAL_KEY_FILE: ${ORBIT_CREDENTIAL_KEY_FILE:-}
ORBIT_CONSOLE_QUEUE_ID: ${ORBIT_CONSOLE_QUEUE_ID:-} ORBIT_CONSOLE_QUEUE_ID: ${ORBIT_CONSOLE_QUEUE_ID:-}
ORBIT_METRICS_ADDR: ${ORBIT_METRICS_ADDR:-} ORBIT_METRICS_ADDR: ${ORBIT_METRICS_ADDR:-}
ports: ports:

148
deploy/local/README.md Normal file
View File

@@ -0,0 +1,148 @@
# 本地 Docker Compose 联调环境
一套长期保留数据的 Orbit + MySQL 测试环境。项目名固定为 `orbit-test`,本机端口 `18080`;复用[基础 Compose](../docker-compose.yml),本目录补充镜像构建、跨服务网络和持久归档卷。
## 启动
此部署工具随 `main` 分支交付;使用当前 main 代码,新接入建议固定 SDK v0.1.2;既有 SDK v0.1.1 可继续使用原接口。需要 Docker Desktop / Docker Compose、Python 3;首次构建镜像需要访问构建依赖。从 Orbit 仓库根目录执行:
```sh
./scripts/orbit-local.py up
```
脚本创建随机数据库密码和管理员密码,构建镜像,依次完成 MySQL 健康检查、前向迁移、运行账号权限收紧、结构核验、管理员/测试身份初始化及服务启动。成功后还检查 readiness 和实际 SDK 队列权限。
启动状态:
```sh
./scripts/orbit-local.py status
```
`mysql` 和 `orbit` 长期运行;`migrate`、`grant`、`verify`、`archive-init` 显示 `Exited (0)` 是一次性初始化成功。
## 控制台与接入地址
| 用途 | 地址/配置 |
| --- | --- |
| 本机控制台 | <http://127.0.0.1:18080/console/> |
| 本机 API / SDK baseURL | `http://127.0.0.1:18080` |
| Docker 网络 | `orbit-test-services` |
| 同网络容器 API / SDK baseURL | `http://orbit-test:8080` |
| Worker WebSocket | 上述主机的 `/v1/worker/connect`;SDK 自动处理升级与鉴权 |
| 结果通知 | 使用 SDK 持久订阅 + EventConsumer,参见[消费手册](../../docs/sdk/event-consumer.md) |
| 就绪检查 | `/health/ready` |
| 管理员 | `admin` |
| 管理员密码 | 本机 `.local/compose-test/admin.password` |
浏览器直接账号密码登录,自动使用同源地址,不需要上传凭据 JSON。MySQL 仅在环境内部网络开放,业务服务通过 Orbit API 接入。
## 为其他应用分配独立配置
登录后打开侧栏「应用接入」,新建应用并选择能力,成功后复制/下载该应用的 `.env`。详情可以随时查看队列、权限和有效期。页面平滑换证默认保留旧 Token 7 天,过渡期内新旧 Token 均按各自有效期核验,原任务和订阅保持不变;全部服务切换并收尾后才可提前结束过渡。管理员可以随时「查看接入信息」「复制接入配置」或下载 orbit.env,过渡期也可以获取当前新 Token。旧凭据仅有摘要时先导入已保存的当前 Token,保留现有有效期和业务身份。
`host.env` / `docker.env` 是初始 local-testing 应用的联调身份;独立应用应使用页面分配的自己的配置。应用接入管理只授权 `admin`,无需创建多角色。[详细操作和恢复手册](../../docs/api/console-applications.md)。
## 本机业务服务
初始化生成 `.local/compose-test/host.env`,包含:
```text
ORBIT_URL=http://127.0.0.1:18080
ORBIT_TOKEN=自动生成的真实令牌
ORBIT_NAMESPACE_ID=自动生成的命名空间ID
ORBIT_QUEUE_ID=自动生成的队列ID
```
在仓库根目录加载,再启动自己的服务:
```sh
set -a
. ./.local/compose-test/host.env
set +a
# 在当前环境中启动你的业务进程
```
这些变量由业务配置代码读取,再传给 SDK;SDK 本身不自动加载 env 文件:
```go
client, err := orbit.NewClient(os.Getenv("ORBIT_URL"), orbit.Options{
Token: os.Getenv("ORBIT_TOKEN"),
})
if err != nil { return err }
queueID := os.Getenv("ORBIT_QUEUE_ID")
```
SDK 安装、任务处理器和完整服务见[根 README](../../README.md#sdk-怎么调用)、[HTTP 接入例子](../../examples/http-service/README.md)。业务处理器由接入服务注册运行;平台不会自动执行业务代码。
## 其他 Docker Compose 服务
在业务 Compose 中接入共享网络,并引用本机生成的 `docker.env`。将下方路径换为本机 Orbit 仓库的绝对路径;这份文件含真实令牌,不提交到业务 Git。
```yaml
services:
app:
# 这里保留业务服务自己的 image/build、ports 等配置
env_file:
- /absolute/path/to/orbit/.local/compose-test/docker.env
networks:
- default
- orbit-test
networks:
orbit-test:
external: true
name: orbit-test-services
```
业务服务读取到的 `ORBIT_URL` 为 `http://orbit-test:8080`,HTTP 和 WebSocket 都通过共享网络访问;Docker 内不要把 `127.0.0.1:18080` 当成宿主机地址。先启动 Orbit 环境,再启动业务 Compose。
如果仅临时联调一个已运行容器,可以执行 `docker network connect orbit-test-services <业务容器名>`,并在该业务服务配置中设置上述 URL 和凭据;容器重建后应采用 Compose 声明网络。
## 运行示例与看数据
宿主机有 Go 1.27.1 时,从仓库根目录执行:
```sh
export ORBIT_URL=http://127.0.0.1:18080
export ORBIT_CREDENTIALS_FILE="$PWD/.local/compose-test/sdk.credentials.json"
cd examples
go run ./worker
go run ./schedules
go run ./workflow
go run ./event-protocol
```
Worker 返回三条 `SUCCEEDED`;计划示例实际执行后暂停;流程示例完成并行、信号和审计核对;事件示例验证通知、ACK 与断线重报。刷新控制台即可查看真实数据。短示例每次产生新测试记录,不是长期业务消费者。
## 日常命令与持久化
```sh
./scripts/orbit-local.py logs # 默认显示 Orbit 最近 100 行
./scripts/orbit-local.py logs mysql # 数据库日志
./scripts/orbit-local.py restart # 只重启 Orbit,等到 ready
./scripts/orbit-local.py stop # 停止本环境的 Orbit 和 MySQL
./scripts/orbit-local.py start # 启动已有容器,等到 ready
./scripts/orbit-local.py up # 初次部署/重建镜像与容器;复用原密码和身份
```
数据库卷为 `orbit-test_orbit-mysql`,归档卷为 `orbit-test_orbit-archives`,容器配置 `restart: unless-stopped`。停止、重启、重新构建都保留数据。私密配置目录 `.local/compose-test` 也要保留;仅留下卷而丢失密码文件不能当成全新安装。
归档卷预算 1 GiB,归档计划和保留策略通过控制台配置,默认不自动开启计划;目前导出保留源数据。不要为腾空间删除数据库卷。
默认使用 `10.253.240.0/24` 内部网络和 `10.253.241.0/24` 服务网络,避免占用已耗尽的 Docker 默认子网池。如与本机已有网络冲突,在私密 `compose.env` 中设置 `ORBIT_TEST_BACKEND_SUBNET`、`ORBIT_TEST_SERVICES_SUBNET` 后首次启动;已有网络需要先协调连接服务后再调整。
配置统一从 `.local/compose-test/compose.env` 读取,脚本隔离其他项目的同名环境变量。可查看原始配置:[基础文件](../docker-compose.yml) + [本地覆盖](compose.yml)。脚本不提供删卷命令;需手工管理时务必固定 Compose 项目 `orbit-test` 和同一份配置。
## 凭据和权限
新建 SDK 凭据默认长期有效(省略 `expires_at`);旧环境保留原策略,可在应用接入页「调整有效期」且不改变 Token。启动输出读取数据库当前有效期。凭据拥有此测试命名空间的任务、Worker、调度、订阅、流程及恢复权限;这是联调身份,正式环境按角色收窄。凭据到期/撤销后不会自动重新初始化或重置历史,按[轮换手册](../../docs/api/authentication.md)处理。
管理员密码、数据库密码、SDK Token 均保存在 `.local/compose-test` 下的私密文件;目录权限 0700、文件权限 0600,Git 和 Docker 构建上下文都排除这些文件。需要其他服务读取时分发 `host.env` / `docker.env`,不要给业务服务数据库管理员配置。
### Token 保管密钥
`up` 自动生成 `.local/compose-test/credential-keys.json`(0600),重复部署复用它。初始化容器将文件放入 `orbit-keys` 卷,供 Orbit 的 65532 用户只读访问;bootstrap/凭据管理 CLI 使用同一源文件。已经启用后发现文件丢失会停止部署,要求恢复原文件,不能生成替代密钥。
备份数据库时单独备份该文件,不提交 Git;不要删除 `orbit-keys` 卷。密钥环、生产多节点部署、旧凭据导入和主密钥变更见[应用接入接口文档](../../docs/api/console-applications.md#8-部署-token-保管)。本地升级会保留原管理员和所有应用身份,历史 Token 需要经管理员导入补齐。
资源退役入口及结清规则见[通用资源退役](../../docs/api/resource-retirement.md)。多队列时先明确选择目标,浏览器按命名空间记忆选择;退役队列不再可导出为新接入配置,历史查询仍开放。

74
deploy/local/compose.yml Normal file
View File

@@ -0,0 +1,74 @@
# 叠加 deploy/docker-compose.yml;使用 scripts/orbit-local.py 固定项目和私密配置。
services:
credential-key-init:
image: mysql:8.4
restart: "no"
user: "0:0"
entrypoint: ["/bin/sh", "-ec"]
command: ["cp /source/credential-keys.json /keys/credential-keys.json.tmp && chown 65532:65532 /keys /keys/credential-keys.json.tmp && chmod 700 /keys && chmod 600 /keys/credential-keys.json.tmp && mv /keys/credential-keys.json.tmp /keys/credential-keys.json"]
volumes:
- ${ORBIT_LOCAL_DIRECTORY}/credential-keys.json:/source/credential-keys.json:ro
- orbit-keys:/keys
archive-init:
image: mysql:8.4
restart: "no"
user: "0:0"
entrypoint: ["/bin/sh", "-ec"]
command: ["chown 65532:65532 /archives && chmod 700 /archives"]
volumes:
- orbit-archives:/archives
bootstrap:
profiles: ["tools"]
image: ${ORBIT_IMAGE}
user: ${ORBIT_LOCAL_USER}
entrypoint: ["/usr/local/bin/orbit-admin"]
command: ["verify"]
environment:
ORBIT_MYSQL_DSN: "root:${ORBIT_DB_ROOT_PASSWORD}@tcp(mysql:3306)/${ORBIT_DB_NAME}?parseTime=true&multiStatements=true"
ORBIT_CREDENTIAL_KEY_FILE: /run/local/credential-keys.json
volumes:
- ${ORBIT_LOCAL_DIRECTORY}:/run/local
orbit:
build:
context: ..
dockerfile: Dockerfile
args:
VERSION: ${ORBIT_BUILD_VERSION}
REVISION: ${ORBIT_BUILD_REVISION}
BUILD_TIME: ${ORBIT_BUILD_TIME}
depends_on:
credential-key-init:
condition: service_completed_successfully
archive-init:
condition: service_completed_successfully
environment:
ORBIT_CONSOLE_APPLICATION_ADMIN: admin
ORBIT_CREDENTIAL_KEY_FILE: /run/orbit-keys/credential-keys.json
ORBIT_ARCHIVE_ROOT: /var/lib/orbit/archives
ORBIT_ARCHIVE_STORAGE_ID: ${ORBIT_ARCHIVE_STORAGE_ID}
ORBIT_ARCHIVE_MAX_BYTES: 1073741824
ORBIT_ARCHIVE_TICK_INTERVAL: 10s
volumes:
- orbit-archives:/var/lib/orbit/archives
- orbit-keys:/run/orbit-keys:ro
networks:
default:
services:
aliases: [orbit-test]
networks:
default:
ipam:
config:
- subnet: ${ORBIT_TEST_BACKEND_SUBNET:-10.253.240.0/24}
services:
name: orbit-test-services
ipam:
config:
- subnet: ${ORBIT_TEST_SERVICES_SUBNET:-10.253.241.0/24}
volumes:
orbit-keys:
orbit-archives:

View File

@@ -81,6 +81,7 @@ server {
} }
# 控制台登录额外限制来源 IP 的尝试速率;业务任务速率仍由 Orbit 的持久化配额和授权决定。 # 控制台登录额外限制来源 IP 的尝试速率;业务任务速率仍由 Orbit 的持久化配额和授权决定。
# Orbit 另有数据库持久化账号/IP 保护;配置 ORBIT_CONSOLE_TRUSTED_PROXIES 为此代理的实际地址。
location = /console/auth/login { location = /console/auth/login {
limit_req zone=orbit_console_login burst=5 nodelay; limit_req zone=orbit_console_login burst=5 nodelay;
proxy_pass http://orbit_backend; proxy_pass http://orbit_backend;

View File

@@ -274,3 +274,14 @@ Event.WorkflowID为只读STORED生成列,从原不可变事件派生流程归
`orbit_archive_jobs` 固定范围和卷,保存 PENDING/RUNNING/SUCCEEDED/FAILED/ABANDONED 状态、版本、领取次数、已确认的批数/根数/字节/链摘要,以及随机租约代次和截止。租约确认必须匹配代次与版本且未过期;人工操作需要原版本、幂等键与审计原因。两个表均无外键,关联在同一事务按命名空间核验。 `orbit_archive_jobs` 固定范围和卷,保存 PENDING/RUNNING/SUCCEEDED/FAILED/ABANDONED 状态、版本、领取次数、已确认的批数/根数/字节/链摘要,以及随机租约代次和截止。租约确认必须匹配代次与版本且未过期;人工操作需要原版本、幂等键与审计原因。两个表均无外键,关联在同一事务按命名空间核验。
数据库与文件不做跨资源事务。持久文件是恢复依据,数据库链前缀是可信核验锚点;文件发布后确认丢失,由原作业重新读文件校验后收敛,缺失文件不自动重建。见[接口与部署说明](api/archive-scheduler.md)。 数据库与文件不做跨资源事务。持久文件是恢复依据,数据库链前缀是可信核验锚点;文件发布后确认丢失,由原作业重新读文件校验后收敛,缺失文件不自动重建。见[接口与部署说明](api/archive-scheduler.md)。
### 当前 Token 保管(000033)
`orbit_credentials.secret_key_id` 指向独立文件中的主密钥;`secret_ciphertext` 保存 AES-256-GCM 的 nonce 与认证密文,两字段同时为空或非空。原文不进入持久化模型、日志和审计。既有摘要保留用于认证,旧记录通过管理员导入当前原文补存,不改变身份、版本、有效期或过渡截止。撤销清空密文,轮换原子替换当前摘要与密文;无外键。
## 000034:通用资源退役
- `pulse_queues.retired_at`:UTC 永久退役时间,NULL 表示未退役;退役必须 paused=true。
- `orbit_subscriptions.retired_at`:UTC 永久退役时间,NULL 表示仍占活动名额。
- `orbit_subscriptions.retired_sequence`:退役事务锁定的命名空间结果流提交水位,NULL 表示未退役;退役后 enabled=false、pending_count=0。
- `ix_subscription_active(namespace_id,retired_at)` 用于活动名额统计。无外键、不删除历史、不回收名称;审计与幂等回执和退役状态同事务。

View File

@@ -259,3 +259,102 @@ A04派发已提交而消息尚未到达Worker的精确进程故障已通过[专
- 已交付完整 HTTP 宿主:业务接口、发送器、Worker、持久 Inbox、健康检查、后台错误传播、有界关闭和数据库最后释放。 - 已交付完整 HTTP 宿主:业务接口、发送器、Worker、持久 Inbox、健康检查、后台错误传播、有界关闭和数据库最后释放。
- 已通过:标准竞态测试、vet/build、SDK隔离和文档链接;定向真实MySQL/平台回归与平台全量 integration 均退出0。包括事务回滚/重复/旧快照、确认回滚、提交回执丢失、强杀恢复和SIGTERM收尾。 - 已通过:标准竞态测试、vet/build、SDK隔离和文档链接;定向真实MySQL/平台回归与平台全量 integration 均退出0。包括事务回滚/重复/旧快照、确认回滚、提交回执丢失、强杀恢复和SIGTERM收尾。
- [公共包接口](sdk/outbox-mysql.md)、[完整调用和故障示例](examples/http-service.md)、[验收报告](reports/outbox-http-integration.md)。本批不扩展到其他数据库/ORM、流程命令Outbox或源数据删除。 - [公共包接口](sdk/outbox-mysql.md)、[完整调用和故障示例](examples/http-service.md)、[验收报告](reports/outbox-http-integration.md)。本批不扩展到其他数据库/ORM、流程命令Outbox或源数据删除。
### main、正式版本与统一示例(本批已完成)
- 根 examples 统一 27 个可运行场景,各目录 README 说明用途、权限、运行和结果;首页改为完整功能与接入入口。
- 开发工作区、构建、MySQL/控制台/历史 SDK 回归同步迁移路径;SDK 保持独立模块。
- 使用 main 与 v0.1.1 / sdk/go/v0.1.1 / adapters/outbox/mysql/v0.1.1 交付,旧标签不变;业务固定版本,无需开发分支或提交号。
- 标准 7 模块回归、SDK/协议/文档门禁、真实 MySQL 全量、控制台端到端及历史任务 API 双向 smoke 均通过;main 与三组 v0.1.1 标签已推送,仓库外空缓存安装两个模块、构建、HTTP smoke 及校验和验证通过,无 replace;证据见[发布记录](reports/v0.1.1-release.md)。
### 本地 Compose 联调环境(2026-09-27)
- 已提供 `scripts/orbit-local.py` 和本地 Compose 覆盖文件,部署在独立项目 orbit-test,主机端口 18080;MySQL/归档卷持久保存,迁移账号与运行账号分离。
- 初始化单管理员、完整测试身份和 host.env/docker.env,私密内容位于被 Git 与 Docker 构建排除的 .local/compose-test;重复启动复用原身份,不重置密码或数据。
- 提供 orbit-test-services 共享网络与 http://orbit-test:8080 地址,固定可配置子网,解决本机默认 Docker 地址池耗尽的问题。
- 已验证:真实容器构建/迁移/零外键/权限收紧;浏览器登录协议和未登录跳转;另一容器运行 Worker 完成三项任务及事件 ACK 重报;定时/流程示例;重复部署与 Orbit/MySQL 停止再启动后原任务、身份保持。
- 接入、账号位置、启动/停止及网络声明见[本地部署手册](../deploy/local/README.md)。这是本地联调环境,不改变平台或 SDK 协议。
### 单管理员应用接入(2026-09-27)
- 新增独立应用接入页:应用/环境分页、队列及凭据详情、选择业务能力新建应用、重新生成 Token、复制/下载 SDK 配置;沿用单管理员,不引入角色系统。
- 新增 Cookie 专用管理接口,部署显式指定唯一登录名;同事务校验管理员与有效会话,写入要求同源与专用请求头。最初采用摘要模式;后续管理员接入信息功能已改为当前 Token 加密保管,普通列表仍无秘密。
- 新建资源/审计/幂等回执同事务,轮换复用现有凭据 ID 与轮换核心。请求不明保留原操作,原样重报;原有任务、订阅和交付身份不变。无新表、无外键、无 SDK 协议修改。
- 已通过定向 MySQL 并发创建、幂等冲突、重名回滚、轮换/旧 Token 拒绝、退出失效与审计脱敏;真实 HTTP 已验证创建、轮换后原任务和订阅可读。标准/全量集成和页面验收记录见[本批报告](reports/console-applications.md)。
- [页面使用、HTTP 接口及故障恢复](api/console-applications.md)。
### 长期凭据与平滑换证(2026-09-27)
- 新建应用和 bootstrap 默认长期 Token,可选定期;既有 Token 可通过管理端/CLI 原地调整有效期,无需改业务配置。
- 000032 与基线增加旧摘要/固定截止,无外键。控制台/CLI 默认 7 天过渡;同一身份的 API、WS 控制命令和跨节点重连均核验两代有效性,权限与任务归属保持不变。
- 结束过渡、两代同时撤销、过渡期防重复换证、旧 v1 固定操作兼容、幂等审计及中文模型注释随功能交付。
- 验证结果见[长期凭据与平滑换证](reports/credential-overlap.md)。SDK 无接口修改;调用方须在截止前滚动更新配置并收尾在途执行。
### 控制台应用范围与列表归属(2026-09-27)
- 已实现:页顶应用/环境与队列筛选、列表和详情应用标签、URL 保持筛选;切换隔离旧请求和表单,错误范围不降级读取默认数据。
- 单管理员通过 Cookie 显式选择范围;业务事务重新核验会话与目标应用,SDK 不支持范围覆盖,订阅原凭据绑定不变。
- 同步提供[范围接口](api/console-scope.md)、真实 MySQL 授权/审计/退出后拒绝测试和 HTTP 列表及订阅管理回归。最终结果见[本批报告](reports/console-scope.md)。
### 换证过渡状态提示(2026-09-27)
- 凭据卡片明确区分过渡中与已撤销状态,展示旧 Token 实际截止及服务切换步骤;入口可点击「查看原因」打开只读说明,到期后页面刷新恢复换证入口。
- 单独说明当前 Token 的获取位置、凭据 ID 与 Token 的区别、过渡期配置可能仍是旧代,以及未保存时的处理方式;新建/换证前、成功交付与关闭确认均提示原文只显示一次。
- 保留过渡期禁止重复换证的保护;提前结束仍需管理员确认服务全部切换、在途任务收尾,不自动结束过渡或替换现有凭据。
- 回归范围:标准竞态测试、vet/build、JavaScript 语法和文档链接;本地页面核对过渡原因可点击、凭据获取说明、正常换证入口与结束过渡确认弹窗。说明同步到[应用接入手册](api/console-applications.md)。
- 已完成验收:基础回归通过;浏览器验证过渡原因点击、说明展开/关闭/再次打开、普通换证与新建保存提醒、结束过渡确认。验收没有轮换或停用现有应用凭据。
- 本地接入命令已实跑:仓库外独立模块安装 SDK v0.1.1、读取队列及校验和通过;真实 Worker 三项成功且排空、结果订阅跨连接 ACK 去重、共享 Docker 网络就绪检查均通过。本地部署手册同步修正旧 Token 过渡语义。
### 管理员接入信息与 Token 保管(本批)
- [x] 当前 Token 加密保存;查看/导入同事务审计,单管理员 Cookie 与同源校验,列表脱敏。
- [x] 「查看接入信息」「复制接入配置」「下载 orbit.env」,包含地址、应用/命名空间/队列与当前 Token。
- [x] 新建/换证/撤销密文与摘要同步,原有效期和过渡策略保持;历史凭据导入校验当前摘要。
- [x] 前向迁移 000033、中文模型注释、无外键;本地 Compose 持久主密钥与丢失保护。
- [x] 标准回归、完整 MySQL/SDK/进程恢复、控制台端到端和浏览器验证通过;本地数据库升级为 33,原身份保持。见[验收报告](reports/credential-token-vault.md)。历史凭据仅有摘要时仍需导入当前原文,不会自动重置。
## 2026-09-27:通用资源退役与接入选择
范围:不含接入方名称或业务判断。迁移 000034、队列/订阅退役 API 与 SDK、活动订阅名额提示、管理端退役入口、按命名空间记忆队列、未补存 Token 文案、可运行示例。
保护:未完成/未知任务、执行许可、活动计划和流程、未退役订阅阻止队列退役;积压、未确认和耗尽交付阻止订阅退役。退役不删历史或审计,不修改凭据。
进度:实现完成;标准七模块竞态回归、vet/build、SDK/协议/文档门禁、真实 MySQL 完整 integration、控制台 HTTP 端到端均通过。浏览器与本地部署、远端版本交付记录见[本批报告](reports/resource-retirement.md)。
## 2026-09-29:管理端简化与操作体验
- [x] 全站统一浅色工作台、分组导航、紧凑统计、中文状态、响应式布局和登录页。
- [x] 任务/流程按状态、业务键、时间服务端筛选;四个资源列表真实游标翻页与 ID 定位,刷新保持范围与筛选。
- [x] 首页明确最近窗口口径,提供待处理入口;应用页集中接入配置,收起技术细节和低频管理操作。
- [x] 浏览器验证、查询/翻页回归、基础构建与控制台端到端,本地 Docker 更新和对接说明同步。验收见[管理端改版记录](reports/console-refresh.md)。
不修改业务执行内核、权限、Token、数据库模型或既有业务资源。
## 2026-09-29:筛选、分页与大屏布局细化
- [x] 应用/队列搜索选择、统一状态和每页条数菜单、筛选控件对齐。
- [x] 四个资源列表默认每页 10 条,保留服务端游标与原条件。
- [x] 登录页左侧内容居中、主工作区最大宽度与移动布局调整。
- [x] 浏览器交互及分页回归、基础构建、本地 Docker 部署与文档同步;见[验收记录](reports/console-refresh.md)。
## 2026-09-29:滚动稳定性与登录保护核对
- [x] 控制台独立内容滚动,固定导航与页头,保留移动端导航和表格横向滚动。
- [x] 应用详情相同快照不重建,后台刷新在滚动/编辑/展开详情时让位,检查请求返回时的交互状态。
- [x] 核对当时登录实现的失败次数封控和登录限流缺口;后续已在下方专项补齐。
- [x] 浏览器滚动、刷新和切页回归,基础检查及持久 Docker 部署;验收见[管理端改版记录](reports/console-refresh.md)。
## 2026-09-30:滚动边界补修与登录保护
- [x] 关闭根页面、侧栏及各内容滚动区的边界回弹;验证连续滚动与短屏导航。
- [x] MySQL 持久化失败窗口、临时锁定及账号/IP 限流,配置校验、可信代理识别。
- [x] 登录成功/失败/拒绝审计,单管理员查询、保留期及有界清理,登录页等待提示。
- [x] 真实 MySQL 并发/跨实例/恢复/审计失败回归,基础检查、浏览器验证、Docker 部署与文档同步。
本地部署修订 `f56f233704700d43c6733b7f0fa14d67e1feddf7`,Schema 35,无外键。基础检查、真实 MySQL、双节点登录与控制台端到端通过;广泛集成在 Docker 暂时无响应处中断,原参数补跑剩余链路全部通过。证据与验证边界见[验收记录](reports/console-refresh.md),默认策略和部署配置见[登录保护](console-login-security.md)。
## 2026-09-30:浏览器页签图标
- [x] 复用现有 Orbit 品牌图形,增加 SVG 和 16/32/48 像素 ICO 图标,登录页与管理端共用。
- [x] `make test vet build docs-check` 通过;本地部署修订 `d47d0d361d7edbcadf5728013cebcf1a2b908cc7`。未登录可请求两种图标,HTTP 200、媒体类型与文件内容正确;登录页与实际控制台均引用图标,readiness 为 ready。

View File

@@ -21,10 +21,10 @@ docker image inspect registry.example/orbit:dev --format '{{.Id}}'
```sh ```sh
docker build --platform linux/amd64 \ docker build --platform linux/amd64 \
--build-arg VERSION=1.0.0 \ --build-arg VERSION=v0.1.1 \
--build-arg REVISION="$(git rev-parse HEAD)" \ --build-arg REVISION="$(git rev-parse HEAD)" \
--build-arg BUILD_TIME="$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ --build-arg BUILD_TIME="$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
-t registry.example/orbit:1.0.0 . -t registry.example/orbit:v0.1.1 .
``` ```
镜像同时写入 OCI `org.opencontainers.image.version`、`org.opencontainers.image.revision` 和 `org.opencontainers.image.created` 标签;可以先核对标签,再在节点启动后通过 `GET /version` 核对进程实际使用的值。`registry.example` 只是占位符,不是平台依赖。 镜像同时写入 OCI `org.opencontainers.image.version`、`org.opencontainers.image.revision` 和 `org.opencontainers.image.created` 标签;可以先核对标签,再在节点启动后通过 `GET /version` 核对进程实际使用的值。`registry.example` 只是占位符,不是平台依赖。
@@ -33,7 +33,7 @@ docker build --platform linux/amd64 \
```sh ```sh
docker run --rm --entrypoint /usr/local/bin/orbit-admin \ docker run --rm --entrypoint /usr/local/bin/orbit-admin \
registry.example/orbit:1.0.0 release manifest > orbit-release-manifest.json registry.example/orbit:v0.1.1 release manifest > orbit-release-manifest.json
``` ```
清单把当前构建身份、协议版本和内置迁移校验和固定下来;部署前再用 `orbit-admin verify` 对目标数据库逐项核对。两者不一致时停止发布,不通过人工修改清单来“对齐”。 清单把当前构建身份、协议版本和内置迁移校验和固定下来;部署前再用 `orbit-admin verify` 对目标数据库逐项核对。两者不一致时停止发布,不通过人工修改清单来“对齐”。
@@ -60,7 +60,7 @@ docker run --rm \
--env ORBIT_MYSQL_DSN \ --env ORBIT_MYSQL_DSN \
--entrypoint /usr/local/bin/orbit-admin \ --entrypoint /usr/local/bin/orbit-admin \
-v "$PWD/orbit-release-manifest.json:/run/orbit-release-manifest.json:ro" \ -v "$PWD/orbit-release-manifest.json:/run/orbit-release-manifest.json:ro" \
registry.example/orbit:1.0.0 verify --manifest /run/orbit-release-manifest.json registry.example/orbit:v0.1.1 verify --manifest /run/orbit-release-manifest.json
docker run --rm \ docker run --rm \
--env ORBIT_MYSQL_DSN \ --env ORBIT_MYSQL_DSN \
@@ -101,3 +101,7 @@ GET /version 版本、提交和协议身份
## 4. 发布验收 ## 4. 发布验收
镜像构建通过只证明发布物可复现,不等于生产高可用。发布候选仍需按[交付核对清单](release-checklist.md)完成真实 MySQL 回归、滚动替换、复制切换、容量、备份恢复和 RPO/RTO 验收。业务 Worker 继续独立部署,通过 HTTP/WebSocket SDK 接入。 镜像构建通过只证明发布物可复现,不等于生产高可用。发布候选仍需按[交付核对清单](release-checklist.md)完成真实 MySQL 回归、滚动替换、复制切换、容量、备份恢复和 RPO/RTO 验收。业务 Worker 继续独立部署,通过 HTTP/WebSocket SDK 接入。
### 管理员 Token 保管文件
启用 `ORBIT_CONSOLE_APPLICATION_ADMIN` 的部署必须通过 `ORBIT_CREDENTIAL_KEY_FILE` 指定 JSON 密钥环。将文件以只读卷或编排器 secret 挂载,并赋予容器 UID 65532 读取权限;不要写入镜像。所有节点与管理 CLI 共用密钥环。字段、升级顺序、备份和主密钥轮替见[接入信息部署](api/console-applications.md#8-部署-token-保管)。本地 Compose 自动创建和复用该文件。

View File

@@ -24,16 +24,16 @@ Compose 文件要求显式提供数据库密码,仓库没有默认密码,也
```sh ```sh
docker build \ docker build \
--build-arg VERSION=1.0.0 \ --build-arg VERSION=v0.1.1 \
--build-arg REVISION="$(git rev-parse HEAD)" \ --build-arg REVISION="$(git rev-parse HEAD)" \
--build-arg BUILD_TIME="$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ --build-arg BUILD_TIME="$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
-t orbit:1.0.0 . -t orbit:v0.1.1 .
``` ```
在当前 shell 或 Secret 管理器中注入配置。以下值仅是变量示例,不是生产密码: 在当前 shell 或 Secret 管理器中注入配置。以下值仅是变量示例,不是生产密码:
```sh ```sh
export ORBIT_IMAGE=orbit:1.0.0 export ORBIT_IMAGE=orbit:v0.1.1
export ORBIT_DB_NAME=orbit export ORBIT_DB_NAME=orbit
export ORBIT_DB_USER=orbit_runtime export ORBIT_DB_USER=orbit_runtime
export ORBIT_DB_PASSWORD='从秘密管理器读取' export ORBIT_DB_PASSWORD='从秘密管理器读取'
@@ -152,3 +152,5 @@ docker compose -f deploy/docker-compose.yml -f deploy/docker-compose.ha.yml up -
## 6. 当前边界 ## 6. 当前边界
该文件是可重复的单节点启动基线,不代表自动数据库故障切换、跨故障域多副本、备份恢复或容量目标已经验收。生产上线还需要真实 MySQL 拓扑、滚动替换、凭据轮换、备份恢复、压测和 RPO/RTO 证据;对应门槛以[交付核对清单](release-checklist.md)为准。 该文件是可重复的单节点启动基线,不代表自动数据库故障切换、跨故障域多副本、备份恢复或容量目标已经验收。生产上线还需要真实 MySQL 拓扑、滚动替换、凭据轮换、备份恢复、压测和 RPO/RTO 证据;对应门槛以[交付核对清单](release-checklist.md)为准。
启用应用接入管理员时,还须配置 `ORBIT_CREDENTIAL_KEY_FILE` 并在 Compose 覆盖文件中只读挂载对应主密钥文件(容器 UID 65532 可读)。基础 Compose 只传递路径,不生成生产秘密;[本地 Compose](../deploy/local/README.md)提供自动初始化。参见[Token 保管配置](api/console-applications.md#8-部署-token-保管)。

View File

@@ -1,6 +1,6 @@
# Orbit HTTP / WebSocket 接口手册 # Orbit HTTP / WebSocket 接口手册
更新:2026-09-18。接口实现状态随 [开发计划](../08-development-plan.md) 更新。 更新:2026-09-27。接口实现状态随 [开发计划](../08-development-plan.md) 更新。
## 当前接口状态 ## 当前接口状态
@@ -9,6 +9,7 @@
| `GET /health/live` | 已实现 | [健康检查](health.md) | | `GET /health/live` | 已实现 | [健康检查](health.md) |
| `GET /health/ready` | 已实现,验证数据库、迁移记录及零外键要求 | [健康检查](health.md) | | `GET /health/ready` | 已实现,验证数据库、迁移记录及零外键要求 | [健康检查](health.md) |
| `GET /version` | 已实现,返回版本、提交、构建时间及协议版本,不包含数据库、凭据或租户信息 | [健康检查](health.md) | | `GET /version` | 已实现,返回版本、提交、构建时间及协议版本,不包含数据库、凭据或租户信息 | [健康检查](health.md) |
| `GET /console/scope` 与控制台显式应用范围 | 已实现单管理员应用/环境切换、队列分页和列表归属;SDK 不可覆盖范围 | [应用范围](console-scope.md) |
| 独立监听的 `GET /metrics` | 已实现基础运行指标,默认关闭 | [运行观测](observability.md) | | 独立监听的 `GET /metrics` | 已实现基础运行指标,默认关闭 | [运行观测](observability.md) |
| `/v1/tasks` 提交、查询、分页与待执行取消 | 已实现,P3扩展业务键与创建时间筛选 | [任务接口](tasks.md) / [查询契约](task-queries.md) | | `/v1/tasks` 提交、查询、分页与待执行取消 | 已实现,P3扩展业务键与创建时间筛选 | [任务接口](tasks.md) / [查询契约](task-queries.md) |
| `GET /v1/tasks/{task_id}/source` | 已实现普通、人工重试、计划固定版本及流程历史激活/轮次来源 | [来源查询](task-source.md) | | `GET /v1/tasks/{task_id}/source` | 已实现普通、人工重试、计划固定版本及流程历史激活/轮次来源 | [来源查询](task-source.md) |
@@ -66,3 +67,7 @@ P1 业务接口已遵守下述约定,后续接口继续沿用:
[流程实例筛选分页与权限](workflow-queries.md)已接入,固定筛选沿游标分页,覆盖未执行分支的全部队列权限。 [流程实例筛选分页与权限](workflow-queries.md)已接入,固定筛选沿游标分页,覆盖未执行分支的全部队列权限。
- [周期归档与作业管理](archive-scheduler.md) - [周期归档与作业管理](archive-scheduler.md)
- [控制台应用接入与 Token 管理](console-applications.md)
- [通用资源退役](resource-retirement.md):订阅结清、活动名额释放、队列依赖保护、SDK 与控制台操作。

View File

@@ -121,7 +121,7 @@ curl -X POST "$ORBIT_URL/v1/application/resources:configure" \
## 6. SDK 与可运行场景 ## 6. SDK 与可运行场景
SDK 方法:`GetApplicationResources(ctx)` 和 `ConfigureApplicationResources(ctx, key, request)`。完整双命名空间场景源码:[application-resources](../../sdk/go/examples/application-resources/main.go)。 SDK 方法:`GetApplicationResources(ctx)` 和 `ConfigureApplicationResources(ctx, key, request)`。完整双命名空间场景源码:[application-resources](../../examples/application-resources/main.go)。
在仓库根目录,先用已迁移数据库启动服务,并初始化一个独立、空闲的示例应用: 在仓库根目录,先用已迁移数据库启动服务,并初始化一个独立、空闲的示例应用:
@@ -135,11 +135,11 @@ ORBIT_EXAMPLE_APP_ID=$(sed -n 's/.*"application_id":"\([^"]*\)".*/\1/p' .local/a
go run ./cmd/orbit-admin bootstrap \ go run ./cmd/orbit-admin bootstrap \
--application-id "$ORBIT_EXAMPLE_APP_ID" --namespace second --environment development \ --application-id "$ORBIT_EXAMPLE_APP_ID" --namespace second --environment development \
--queue second --resource-access --output .local/app-second.credentials.json --queue second --resource-access --output .local/app-second.credentials.json
cd sdk/go cd examples
ORBIT_URL=http://127.0.0.1:8080 \ ORBIT_URL=http://127.0.0.1:8080 \
ORBIT_CREDENTIALS_FILE=../../.local/app-first.credentials.json \ ORBIT_CREDENTIALS_FILE=../.local/app-first.credentials.json \
ORBIT_SECOND_CREDENTIALS_FILE=../../.local/app-second.credentials.json \ ORBIT_SECOND_CREDENTIALS_FILE=../.local/app-second.credentials.json \
go run ./examples/application-resources go run ./application-resources
``` ```
预期: 预期:

View File

@@ -2,6 +2,8 @@
状态:P1 已实现。业务接口每次在数据库事务内校验凭据摘要、撤销/到期、应用与命名空间启停,以及动作和队列范围。授权与写入使用同一事务;管理变更与已经获得授权锁的请求按事务先后次序生效。 状态:P1 已实现。业务接口每次在数据库事务内校验凭据摘要、撤销/到期、应用与命名空间启停,以及动作和队列范围。授权与写入使用同一事务;管理变更与已经获得授权锁的请求按事务先后次序生效。
已提供单管理员[应用接入页面](console-applications.md):新建应用、查看队列与凭据、长期凭据、调整有效期、平滑换证、复制 SDK 配置。下方 CLI 继续用于首次安装及运维。
## 初始化一个新的接入应用 ## 初始化一个新的接入应用
前置:专用 MySQL 数据库已经执行 orbit-migrate up,使用持有初始化权限的数据库管理连接。此命令创建新应用、命名空间、队列和凭据,不会覆盖现有同名应用。 前置:专用 MySQL 数据库已经执行 orbit-migrate up,使用持有初始化权限的数据库管理连接。此命令创建新应用、命名空间、队列和凭据,不会覆盖现有同名应用。
@@ -19,7 +21,7 @@ go run ./cmd/orbit-admin bootstrap \
ORBIT_MYSQL_DSN 通过环境注入,命令不读取 .env。所有名称必填,以字母/数字开头,后续允许字母、数字、`_ . : -`;environment 最长 32,其余最长 128。输出文件必须不存在,以 0600 创建;原始凭据不会打印到 stdout/stderr。`.local/` 和 `*.credentials.json` 已被 Git 忽略。 ORBIT_MYSQL_DSN 通过环境注入,命令不读取 .env。所有名称必填,以字母/数字开头,后续允许字母、数字、`_ . : -`;environment 最长 32,其余最长 128。输出文件必须不存在,以 0600 创建;原始凭据不会打印到 stdout/stderr。`.local/` 和 `*.credentials.json` 已被 Git 忽略。
输出 JSON 包含 application_id / namespace_id / queue_id / credential_id / token / expires_at。初始凭据有效期为 30 天,权限包括当前命名空间内的五个 P1 动作和全部队列。初始队列 max_concurrency=4、rate_per_second=10、max_unfinished_tasks=100000;并发、开始限速与积压背压已生效,语义及管理方式见 [队列接口](queues.md)。这些默认值是开发基线,不是容量承诺。 输出 JSON 包含 application_id / namespace_id / queue_id / credential_id / token,可选 expires_at。初始凭据默认长期有效(expires_at 省略),可用 `--valid-for 720h` 显式选择 30 天;0 表示长期,其他值为 1 小时至 365 天。权限包括当前命名空间内的五个 P1 动作和全部队列。初始队列 max_concurrency=4、rate_per_second=10、max_unfinished_tasks=100000;并发、开始限速与积压背压已生效,语义及管理方式见 [队列接口](queues.md)。这些默认值是开发基线,不是容量承诺。
如果希望在第一次初始化时同时创建控制台管理员,可在同一条 bootstrap 事务中提供账号,并从标准输入交付密码: 如果希望在第一次初始化时同时创建控制台管理员,可在同一条 bootstrap 事务中提供账号,并从标准输入交付密码:
@@ -44,7 +46,7 @@ secret-manager read orbit/console-admin-password | \
## 轮换与撤销 ## 轮换与撤销
凭据轮换和撤销只允许在受保护的数据库管理环境执行,不提供公网管理接口。轮换保留 `credential_id`,因此订阅和 Worker 实例的授权绑定仍指向同一记录;新的 Worker 进程必须按现有进程身份规则重新连接,旧令牌不能再通过任何 API 或 WSS 认证。平台不会批量改写在途任务、交付记录或历史会话证据。 管理 CLI 在受保护的数据库管理环境执行;控制台也可由部署指定的单管理员轮换凭据,见[应用接入](console-applications.md)。业务 SDK 不开放凭据管理,撤销仍由 CLI 执行。轮换保留 `credential_id`,因此订阅和 Worker 实例的授权绑定仍指向同一记录;新进程仍遵循原 Worker 身份规则;过渡期内旧 Token 的 API 请求、原 WS 控制命令及跨节点重连都继续有效。新 Token 立即可用,结束过渡或超过截止后旧 Token 才被拒绝。平台不会批量改写在途任务、交付记录或历史会话证据。
先读取脱敏状态和当前版本: 先读取脱敏状态和当前版本:
@@ -61,12 +63,13 @@ go run ./cmd/orbit-admin credential rotate \
--namespace-id <namespace_id> \ --namespace-id <namespace_id> \
--credential-id <credential_id> \ --credential-id <credential_id> \
--expected-revision 1 \ --expected-revision 1 \
--valid-for 720h \ --valid-for 0 \
--grace 168h \
--reason "scheduled credential rotation" \ --reason "scheduled credential rotation" \
--output .local/rotated.credentials.json --output .local/rotated.credentials.json
``` ```
命令先读取并核对版本,生成一个固定 `operation_id`、令牌和绝对到期时间,写入新的 `0600` 私有操作文件,然后提交数据库事务。文件不得已存在;提交结果不明、网络断开或数据库返回未知错误时必须保留文件,并使用同一个文件执行 `credential apply --file`,不能重新执行 `rotate` 生成第二个秘密。`--valid-for` 限定在 1 小时到 1 年。数据库只保存秘密摘要、请求摘要和脱敏回执。 命令先读取并核对版本,生成一个固定 `operation_id`、令牌、可选绝对到期时间和固定过渡截止,写入新的 `0600` 私有操作文件,然后提交数据库事务。文件不得已存在;提交结果不明、网络断开或数据库返回未知错误时必须保留文件,并使用同一个文件执行 `credential apply --file`,不能重新执行 `rotate` 生成第二个秘密。`--valid-for` 默认 0(长期),也可配置 1 小时到 365 天;`--grace` 默认 168h(7 天),范围 0–720h,0 表示立即停用旧 Token。旧 Token 的实际截止取过渡截止与原到期时间的较早者,不复活已过期秘密。数据库保存认证摘要、请求摘要和脱敏回执;配置 ORBIT_CREDENTIAL_KEY_FILE 时还加密保存当前 Token,管理员可查看和复制。[管理员接入信息与密钥配置](console-applications.md#8-部署-token-保管)。
```sh ```sh
go run ./cmd/orbit-admin credential apply \ go run ./cmd/orbit-admin credential apply \
@@ -75,6 +78,36 @@ go run ./cmd/orbit-admin credential apply \
`apply` 会严格拒绝软链接、非 0600 文件、未知 JSON 字段、重复 JSON 对象和修改过的操作内容。重复应用已提交的文件只返回原回执,回执中的 `deduplicated` 为 `true`,不会重新轮换或新增审计。 `apply` 会严格拒绝软链接、非 0600 文件、未知 JSON 字段、重复 JSON 对象和修改过的操作内容。重复应用已提交的文件只返回原回执,回执中的 `deduplicated` 为 `true`,不会重新轮换或新增审计。
### 原 Token 调整有效期
无需换 Token:读取当前 revision 后执行以下命令,业务侧继续使用原配置。缩短有效期同样会生效,应按预期截止配置。
```sh
go run ./cmd/orbit-admin credential expiry \
--namespace-id <namespace_id> --credential-id <credential_id> \
--expected-revision 1 --valid-for 0 \
--reason "service credential remains valid until revoked" \
--output .local/expiry.operation.json
```
### 平滑切换的完整顺序
1. 生成新 Token,保留默认 7 天过渡。凭据 ID、权限、任务、订阅和交付身份不变。
2. 把新 Token 发布到调用方配置,逐台更新 API 服务、Worker 和结果消费者。SDK v0.1.1 的 `Options.Token` 在创建客户端时读取,修改 `.env` 不会自动刷新正在运行的客户端;新建客户端或滚动重启服务,按 [HTTP 宿主示例](../examples/http-service.md) 正常排空在途工作。
3. 在截止前确认所有旧进程已完成任务回报和 ACK,并已经退出或用新 Token 重新连接。HTTP 调用无须整体停机;持续执行能力依赖业务侧保留足够副本。单实例重启本身会产生短暂停顿。
4. 全部切换后可提前结束过渡;否则旧 Token 到时自动失效,认证使用数据库时间,不依赖定时清理。
```sh
go run ./cmd/orbit-admin credential finalize \
--namespace-id <namespace_id> --credential-id <credential_id> \
--expected-revision 2 --reason "all service instances switched and drained" \
--output .local/finalize.operation.json
```
结束过渡立即停用旧 Token,当前 Token 不变。长期 Token 仍受主动撤销、应用/命名空间停用约束。旧代仍在有效过渡期时再次轮换返回 409,避免误伤未切换服务;先完成本次切换。修改当前有效期不延长旧代截止。若旧 Token 本身即将到期而需要更长切换窗口,应先调整当前有效期,再发起换证。
新固定操作文件使用 version=2;历史 version=1 仍按原来的固定到期和立即轮换语义重放,不自动延长旧秘密。
发生泄露或 Worker 必须立即停用时执行撤销: 发生泄露或 Worker 必须立即停用时执行撤销:
```sh ```sh
@@ -86,7 +119,7 @@ go run ./cmd/orbit-admin credential revoke \
--reason "incident response" --reason "incident response"
``` ```
撤销同样先写入固定操作文件,再提交事务;提交不明时用 `credential apply --file .local/revoke.operation.json` 重试。撤销只标记凭据失效,不删除订阅、任务、交付或历史记录。即使应用或命名空间已停用,管理撤销仍可执行。重复应用同一撤销文件只返回原回执,不追加重复审计。审计主体取自 MySQL 管理连接的 `CURRENT_USER()`,审计摘要不包含秘密原文或秘密摘要。 撤销同样先写入固定操作文件,再提交事务;提交不明时用 `credential apply --file .local/revoke.operation.json` 重试。撤销使当前和过渡中的上一代同时失效,不删除订阅、任务、交付或历史记录。即使应用或命名空间已停用,管理撤销仍可执行。重复应用同一撤销文件只返回原回执,不追加重复审计。审计主体取自 MySQL 管理连接的 `CURRENT_USER()`,审计摘要不包含秘密原文或秘密摘要。
## 凭据格式与作用域 ## 凭据格式与作用域
@@ -128,3 +161,7 @@ P3 结果订阅核心新增 `events:read`、`events:manage` 和 `events:consume`
P4定义发布新增`workflows:definitions:read`与`workflows:definitions:publish`,仅显式`--workflow-access`授予。创建/读取元数据作用于命名空间,发布及读取完整版本额外校验全部引用队列;默认提交/Worker凭据不获此权限。发布不创建任务,不要求tasks:submit,详见[定义API](workflow-definitions.md)。 P4定义发布新增`workflows:definitions:read`与`workflows:definitions:publish`,仅显式`--workflow-access`授予。创建/读取元数据作用于命名空间,发布及读取完整版本额外校验全部引用队列;默认提交/Worker凭据不获此权限。发布不创建任务,不要求tasks:submit,详见[定义API](workflow-definitions.md)。
P4/P5实例公共接入增加`workflows:start/read/control/signal/recover`及`workflows:audit:read`。五个独立CLI开关`--workflow-run-access`、`--workflow-control-access`、`--workflow-signal-access`、`--workflow-recovery-access`、`--workflow-audit-access`分别明确授予。前四个同时包含实例读取;audit只授予流程操作审计读取。原`--workflow-access`仍仅授予定义读/发布,任务`--recovery-access`不授予流程恢复。全部固定队列仍按当前凭据校验,详见[实例权限表](workflows.md#1-路由权限与-sdk)。初始化权限集合在交付凭据前校验。 P4/P5实例公共接入增加`workflows:start/read/control/signal/recover`及`workflows:audit:read`。五个独立CLI开关`--workflow-run-access`、`--workflow-control-access`、`--workflow-signal-access`、`--workflow-recovery-access`、`--workflow-audit-access`分别明确授予。前四个同时包含实例读取;audit只授予流程操作审计读取。原`--workflow-access`仍仅授予定义读/发布,任务`--recovery-access`不授予流程恢复。全部固定队列仍按当前凭据校验,详见[实例权限表](workflows.md#1-路由权限与-sdk)。初始化权限集合在交付凭据前校验。
## 部署升级
迁移 `000032` 为凭据表增加上一代摘要与 UTC 截止,并以 CHECK 约束成对为空;不新增外键、不改变已有秘密或有效期。该次基线同步到 32;当前基线还包含后续 000033 Token 加密保管字段。按部署流程应用迁移并更新全部 Orbit 节点后再使用平滑换证;旧版本节点只认识当前摘要,不能在混合版本期间承诺旧 Token 可用。既有凭据不会被迁移自动改为长期,须通过有审计的 expiry 操作显式调整。

View File

@@ -157,4 +157,4 @@ for _, item := range result.Items {
SDK验证输入数量/身份/整体体积及返回数量、顺序、状态和回执归属;不自动重试、拆批或创建新键。`err == nil` 只表示取得可解释的逐项响应。局部错误为 `BatchItemError`,不是顶层APIError;整批HTTP错误仍为APIError,网络错误沿用标准库。独立SDK无数据库依赖。 SDK验证输入数量/身份/整体体积及返回数量、顺序、状态和回执归属;不自动重试、拆批或创建新键。`err == nil` 只表示取得可解释的逐项响应。局部错误为 `BatchItemError`,不是顶层APIError;整批HTTP错误仍为APIError,网络错误沿用标准库。独立SDK无数据库依赖。
完整运行命令、输入输出和收尾见 [批量场景](../examples/batch.md),源码见 [SDK示例](../../sdk/go/examples/batch/main.go),覆盖范围和实际证据见 [回归报告](../reports/phase-3-batch-tasks.md)。旧客户端继续使用单项接口;新SDK调用旧服务该路由会返回404,不会静默退化为其他语义。 完整运行命令、输入输出和收尾见 [批量场景](../examples/batch.md),源码见 [SDK示例](../../examples/batch/main.go),覆盖范围和实际证据见 [回归报告](../reports/phase-3-batch-tasks.md)。旧客户端继续使用单项接口;新SDK调用旧服务该路由会返回404,不会静默退化为其他语义。

View File

@@ -88,13 +88,13 @@ return nil, &orbit.WorkerCancellationConfirmed{
## 4. 可运行场景 ## 4. 可运行场景
源码:[cancellation/main.go](../../sdk/go/examples/cancellation/main.go)。使用 [Worker 初始化](../sdk/worker-runtime.md) 的私有凭据文件,需 tasks:submit/read/cancel、workers:connect/consume 和队列范围。此示例只等待停止提示,没有外部业务副作用。 源码:[cancellation/main.go](../../examples/cancellation/main.go)。使用 [Worker 初始化](../sdk/worker-runtime.md) 的私有凭据文件,需 tasks:submit/read/cancel、workers:connect/consume 和队列范围。此示例只等待停止提示,没有外部业务副作用。
```sh ```sh
cd sdk/go cd examples
ORBIT_URL=http://127.0.0.1:8080 \ ORBIT_URL=http://127.0.0.1:8080 \
ORBIT_CREDENTIALS_FILE=/private/path/worker.credentials.json \ ORBIT_CREDENTIALS_FILE=/private/path/worker.credentials.json \
go run ./examples/cancellation go run ./cancellation
``` ```
预期输出: 预期输出:

View File

@@ -0,0 +1,200 @@
# 控制台应用接入
单管理员在「应用接入」页面创建应用、初始队列与 SDK 凭据,查看环境、队列、权限和有效期,平滑换证,复制或下载 `.env` 配置。业务认证使用 Token 摘要;当前 Token 使用 AES-256-GCM 加密保管。管理员可以随时查看、复制完整接入配置和下载 orbit.env,列表仅返回脱敏元数据。
## 1. 启用和使用
部署配置指定唯一有跨应用接入管理权限的控制台登录名:
```sh
export ORBIT_CONSOLE_APPLICATION_ADMIN=admin
export ORBIT_CREDENTIAL_KEY_FILE=/run/orbit-secrets/credential-keys.json
```
该账号必须已经通过 bootstrap 或 console-user create 创建。配置为空时所有应用接入管理请求返回 403,不会自动提升已有账号;多节点使用相同配置。继续使用单管理员,不引入角色管理系统。现有控制台账号与会话的绑定凭据仍须有效;到期前可在本页轮换。轮换 SDK Token 不改变浏览器独立会话秘密。
本地 Compose 已为 `admin` 配置该入口,访问 `http://127.0.0.1:18080/console/#/applications`。
1. 点击「新建应用」,填写应用名称、环境、命名空间、初始队列和操作原因。
2. 选择 Worker、结果订阅、定时、流程等需要的能力及有效期。基础权限包含任务提交/查询/取消、队列读取/管理。
3. 创建成功后复制或下载完整 `.env`,交给该应用的服务端配置。默认地址使用当前页面来源,详情中可改为容器地址或部署域名。
4. 已接入应用点击「查看接入信息」或「复制接入配置」,获取包含当前 Token 的完整配置;也可下载 orbit.env。
5. 「平滑换证」保留 application_id、namespace_id、credential_id、队列、任务和订阅;新 Token 立即生效,旧 Token 在配置的过渡期内继续使用(页面默认 7 天,支持 1/7/30 天),便于逐台更新配置。详情展示旧 Token 实际截止,全部服务切换后可点「结束过渡」。
6. 默认「长期有效」,不需要每月人工换证;已有凭据可点「调整有效期」直接设为长期,原 Token 保持不变。
凭据卡片提供「查看接入信息」「复制接入配置」。配置包含 ORBIT_URL、ORBIT_APPLICATION_ID、ORBIT_NAMESPACE_ID、ORBIT_QUEUE_ID、ORBIT_TOKEN;可直接粘贴为环境配置。先选择业务服务实际可访问的地址和队列,再复制;应用 ID 用于识别,真正认证身份来自 Token。过渡期始终返回当前新 Token,调整有效期或结束旧代过渡后仍可查看。历史凭据尚无密文时提供「导入当前 Token」,不能把仍可用的旧代 Token 导入为当前代次。
环境与命名空间形成隔离边界。不同应用应分别创建;同一应用的多个命名空间在列表中分别展示。页面支持新建应用及其初始队列;业务列表可通过应用筛选栏切换范围,分别展示各应用数据。未提供应用删除、身份迁移或现有应用新增命名空间的表单;已有 CLI 的 `--application-id` 仍可增加命名空间,队列 SDK 可增加同范围队列。
## 2. 路由与认证
这些是浏览器管理端接口,不属于业务 SDK。只接受有效的 `orbit_console_session` HttpOnly Cookie,并在数据库事务中重新核验部署指定的管理员账号和会话;即使 SDK 凭据拥有全部业务权限也不能访问。
| 方法与路径 | 用途 |
| --- | --- |
| `GET /console/applications?after=<namespace_id>` | 按命名空间 ID 升序读取 50 条接入范围,返回 `items`、可选 `next`;`after` 为排他起点 |
| `GET /console/applications/{namespace_id}` | 应用/环境详情、最多 100 个队列和 100 张脱敏凭据;超出返回 `truncated=true` |
| `POST /console/applications/prepare` | 校验意图,生成固定操作 ID、资源 ID、Token、绝对到期时间;不创建资源、不轮换秘密 |
| `POST /console/applications/apply` | 提交准备结果,原样重报返回原脱敏回执 |
| `POST /console/applications/{namespace_id}/credentials/{credential_id}/token/reveal` | 管理员读取当前 Token;审计成功后才返回 |
| `POST /console/applications/{namespace_id}/credentials/{credential_id}/token/import` | 校验并加密补存当前 Token,不轮换身份 |
POST 必须有 `Content-Type: application/json` 和 `X-Orbit-Console: 1`;浏览器 Origin 必须匹配当前主机,拒绝跨站 Fetch Metadata,不提供跨域授权。响应禁止缓存,成功信封为 `{"data": ...}`。未知字段、重复 JSON 键、显式 null 和错误类型被拒绝,正文上限 512 KiB。
## 3. 新建应用
prepare 请求:
```json
{
"kind": "CREATE",
"application": "order-service",
"namespace": "default",
"environment": "test",
"queue": "orders",
"capabilities": ["worker", "events", "schedules", "workflows"],
"expected_revision": "0",
"valid_days": 0,
"reason": "接入订单服务"
}
```
名称以字母或数字开头,后续只允许字母、数字、`_ . : -`,environment 最长 32,其余最长 128。valid_days 为 0–365 的整数,默认 0 表示长期有效;reason 非空、最多 1024 个 Unicode 字符,不含换行或 NUL。capabilities 可选 `worker`、`events`、`schedules`、`workflows`、`recovery`、`resources`,不可重复。新建不传 namespace_id / credential_id,expected_revision 省略或为字符串 `"0"`。
prepare 响应 data 为固定操作对象:
```json
{
"version": 2,
"input": {"kind":"CREATE","application":"order-service","namespace":"default","environment":"test","queue":"orders","capabilities":["worker","events"],"expected_revision":"0","valid_days":0,"reason":"接入订单服务"},
"operation_id": "11111111111111111111111111111111",
"application_id": "22222222222222222222222222222222",
"namespace_id": "33333333333333333333333333333333",
"queue_id": "44444444444444444444444444444444",
"credential_id": "55555555555555555555555555555555",
"token": "服务端生成的完整 Token"
}
```
以上是结构示意,ID、令牌及时间以服务端返回为准。将 **data 整体原样** POST 到 apply,不包 `data` 外层。应用、额度、命名空间、队列、凭据摘要、Token 密文、审计和幂等回执在同一事务提交。初始队列并发 4、开始速率 10/秒,沿用 bootstrap 默认策略;凭据队列范围为新命名空间的全部队列。重名应用返回 409,不覆盖原资源。
## 4. 平滑换证
prepare 请求:
```json
{
"kind": "ROTATE",
"namespace_id": "33333333333333333333333333333333",
"credential_id": "55555555555555555555555555555555",
"expected_revision": "1",
"valid_days": 0,
"grace_days": 7,
"reason": "更新接入凭据"
}
```
expected_revision 为读取到的字符串版本。只允许上述轮换字段,不混入新应用名称或能力组。准备对象包含原 application_id / namespace_id / credential_id,没有 queue_id。apply 复用原有凭据轮换事务:将原摘要保留到固定过渡截止,原子替换当前摘要、密文与可选到期时间,版本加一,保存脱敏回执及人类账号审计;权限组不改变。已撤销的凭据禁止变更。ROTATE 的 grace_days 范围 0–30,API 省略/0 保持立即停用旧 Token 的兼容语义,页面显式提交 7;实际截止不超过旧 Token 原到期时间。过渡未结束时再次轮换返回 409。
页面在过渡期将入口标为「暂不可换证 · 查看原因」,同时显示实际截止和切换步骤。该入口可以点击,打开只读说明弹窗,不会提交换证或结束过渡。这表示上一轮换证已生效;再次轮换会挤掉仍在使用的旧 Token,所以暂时禁止。将已保存的新 Token 配置到所有服务、Worker 和结果消费者,并收尾在途任务。到期后页面刷新会恢复换证入口;只有确认全部切换完成,才可提前点「结束过渡,停用旧 Token」。结束过渡会立即停用旧 Token,不能仅为解锁按钮而操作。已撤销凭据单独显示「已撤销 · 查看原因」,同样只打开说明。
apply 成功 data:
```json
{
"operation_id": "11111111111111111111111111111111",
"application_id": "22222222222222222222222222222222",
"namespace_id": "33333333333333333333333333333333",
"credential_id": "55555555555555555555555555555555",
"revision": "2",
"deduplicated": false
}
```
## 5. 调整有效期与结束过渡
prepare 输入示例:
```json
{
"kind": "SET_EXPIRY",
"namespace_id": "33333333333333333333333333333333",
"credential_id": "55555555555555555555555555555555",
"expected_revision": "2",
"valid_days": 0,
"reason": "服务凭据设置为长期有效"
}
```
SET_EXPIRY 不生成新 Token,只更新当前有效期;valid_days=0 为长期,1–365 为从准备时间计算的天数。FINALIZE 使用相同身份/版本字段,kind 改为 FINALIZE,valid_days 必须为 0,用于提前停用旧 Token。两者均禁止 grace_days 和新建字段,prepare 不返回 token;FINALIZE 也不返回 expires_at。apply 使用完整原对象,具有相同的并发版本、幂等和审计约束。
新版 prepare 对象带 version=2;expires_at 为空时**省略字段**,不要传显式 null。ROTATE 有过渡期时另外包含固定 previous_valid_until;详情中的 previous_valid_until 是受旧到期时间约束后的实际截止,未设置时省略。详情/回执不会返回旧秘密。历史不带 version 的固定操作仍按原语义重放。
完整滚动更新及 SDK 客户端生命周期说明见[凭据手册](authentication.md)。更换配置不会自动刷新已创建的客户端,须在过渡截止前完成重建或逐台重启并排空在途任务。
## 6. 超时、重复和审计
- 页面提交前把整个固定操作保留在当前内存;请求超时或结果未知时,按钮变成「重试确认」,重用同一份内容。不能再次 prepare 来代替核对。
- 页面允许「保存待核对操作」下载私密 JSON;含真实 Token,应放到受限目录。恢复时登录同一管理员后,向 apply 发送该文件正文。不要把 Cookie 或操作文件提交 Git,也不要放到 URL。
- 关闭窗口后清除浏览器中的明文,管理员可以重新查看,无需再次换证。
- 原操作返回的回执是历史快照,可能已被后续轮换替代。页面会重新读取当前凭据版本后才展示配置。
- 管理审计主体是 `console:<user_id>`;正文只有权限、资源 ID、到期时间等元数据。列表、审计、幂等回执和业务记录都不保存秘密原文。
- 当前管理员退出、会话过期或账号停用后不能重放管理操作。SDK Token 撤销/到期与控制台登录资格沿用既有账号绑定约束。
| 错误 | HTTP | 处理 |
| --- | --- | --- |
| UNAUTHENTICATED | 401 | 登录有效控制台账号 |
| PERMISSION_DENIED | 403 | 核对唯一管理员配置、会话及同源请求 |
| INVALID_ARGUMENT | 400 | 核对字段、能力组、固定身份及有效期 |
| NOT_FOUND | 404 | 核对命名空间/凭据是否存在 |
| STATE_CONFLICT | 409 | 应用名称已存在、凭据已撤销、版本已变更或旧 Token 仍在过渡期;读取当前状态 |
| IDEMPOTENCY_CONFLICT | 409 | 原操作内容被修改,保留原始操作核对 |
| 数据库/网络故障 | 5xx / 网络错误 | 不假定失败,保留原操作重报 |
可重复运行的真实 HTTP 场景见 [test-console-applications.py](../../scripts/test-console-applications.py),标准容器入口 `make console-e2e` 同时验证此链路。基础 SDK 使用方式见 [SDK 接入](../sdk/README.md)。
业务数据的应用筛选、队列分页及会话隔离见[应用范围接口](console-scope.md)。
## 7. 当前 Token 与历史导入
详情返回 `token_vault_enabled`;每张凭据的 `token_stored` 表示当前 Token 是否已保管。列表、详情、审计和幂等回执都不包含原文。
查看请求:
```json
{"expected_revision":"3"}
```
导入请求:
```json
{"expected_revision":"3","token":"已保存的当前完整 Token"}
```
成功响应:
```json
{"data":{"namespace_id":"33333333333333333333333333333333","credential_id":"55555555555555555555555555555555","revision":"3","token":"当前完整 Token"}}
```
只接受当前凭据版本。版本冲突、撤销或旧记录未保管返回 409;导入的身份或秘密与当前摘要不符返回 400(旧代处于过渡期也不例外);密钥缺失/解密失败返回 503。读取需要 Cookie、同源和 X-Orbit-Console,与其他管理 POST 相同。响应 `Cache-Control: no-store`;审计动作分别是 `console.credential.token.view`、`console.credential.token.import`,不含 Token、摘要或密文。
导入可以重复提交同一当前 Token,每次成功操作记录审计;不修改认证 revision、到期时间、权限或旧代截止。网络结果不明时可重新读取元数据或重报同一导入。读取/导入遇到审计写入失败或提交结果不明,不返回秘密。读取与换证对同一凭据加锁,返回的是该事务看到的当前代次;之后其他管理员的新轮换仍以实际数据库状态为准。
## 8. 部署 Token 保管
启用 `ORBIT_CONSOLE_APPLICATION_ADMIN` 时必须配置 `ORBIT_CREDENTIAL_KEY_FILE`,文件格式:
```json
{"active":"key-v1","keys":{"key-v1":"32 字节随机密钥的标准 Base64 编码"}}
```
主密钥由部署方生成,权限限定运行用户读取;不要使用示例文字作为密钥。所有服务节点和管理 CLI 使用同一份密钥环,通过只读文件挂载部署,不写进镜像、Git 或数据库。参考[本地部署](../../deploy/local/README.md)自动生成方案。最多 16 把密钥,文件最多 64 KiB。密文绑定 namespace_id / credential_id,不能跨凭据替换。
升级先停止旧节点、应用迁移 000033、配置密钥再启动全部新节点;旧写节点不认识密文列,不能混合版本承诺回看一致性。迁移仅增加两个可空字段和成对 CHECK,无外键,不改变已有 Token、版本、有效期或过渡时间。
数据库和密钥文件分别备份。更换主密钥时使用新 key ID,将其设为 active,同时保留仍有密文引用的旧 key;在更新所有节点之前不写新 key ID 的数据。历史密文可以先查看、再导入同一 Token 以重新加密,不需要更换业务 Token。不得将旧 ID 映射到不同密钥,也不得在密文尚未迁移时删除旧 key。
管理 CLI 的 bootstrap / credential rotate / apply 读取同一环境变量。未设置时保持摘要模式,轮换会清除旧密文;之后必须导入该次新 Token 才能回看。控制台启用应用管理员时不会允许遗漏主密钥配置。
历史库仅有 SHA-256 摘要,无法凭摘要重建原文。请从既有业务配置或下载文件导入当前 Token;不要为补存秘密提前结束仍在使用的旧 Token 过渡。

54
docs/api/console-scope.md Normal file
View File

@@ -0,0 +1,54 @@
# 控制台应用范围
此接口服务于内置控制台的单管理员,用于按应用环境读取列表、详情并执行已有管理操作;不是 SDK 的跨应用调用方式。业务服务继续使用自己应用的 Token 和队列。
## 查看范围元数据
`GET /console/scope?after=<queue_id>` 只接受登录 Cookie,返回 `data`:
```json
{
"entry": {
"application_id": "11111111111111111111111111111111",
"application": "sample-app",
"namespace_id": "22222222222222222222222222222222",
"namespace": "default",
"environment": "test",
"enabled": true
},
"queues": [{"id": "33333333333333333333333333333333", "name": "jobs"}],
"can_switch": true
}
```
不指定范围头时返回账号原始应用及授权队列。队列按 ID 升序,每页最多 100 项,存在更多时返回 `next`,下次用 `after=next`;没有更多则省略。应用目录继续使用 `GET /console/applications` 的 50 项分页。名称全部来自数据库,ID 为授权身份,不按应用名称猜测关联。
## 显式选择应用环境
部署配置 `ORBIT_CONSOLE_APPLICATION_ADMIN` 指定的登录管理员可发送:
```http
X-Orbit-Console: 1
X-Orbit-Namespace: 22222222222222222222222222222222
```
以上请求头只能搭配原登录 Cookie,不能搭配 `Authorization`。服务端不签发、不返回新业务 Token,不更改浏览器会话原始归属。部署配置为空或登录名不匹配时拒绝切换。
支持范围:
| 页面 | 请求 | 数据范围 |
| --- | --- | --- |
| 任务执行 | 现有 `/v1/tasks` 列表、详情、历史及管理动作 | 所选命名空间 + 队列 |
| 定时计划 | 现有 `/v1/schedules` 查询、暂停/继续 | 所选命名空间 + 队列 |
| 流程实例 | 现有 `/v1/workflows` 查询、控制和人工恢复 | 所选命名空间,含流程固定版本所有队列 |
| 结果订阅 | 现有 `/v1/subscriptions` 查询、启停和交付重试 | 所选命名空间 + 队列,管理员可管理该范围内不同 SDK 凭据的已有订阅 |
| 保留策略 | `/console/retention`、预览、导出 | 所选命名空间 |
| 归档作业 | `/console/archive/plans`、`jobs` 及原管理动作 | 所选命名空间 |
队列选项仅对任务、计划、订阅生效。此桥接入口不提供创建任务/计划/订阅、发布定义、启动流程、发送信号、Worker 执行或结果消费权限。SDK 原有的权限与订阅归属校验不变。
每个业务事务重新核验管理员账号、原会话、绑定凭据有效性以及原/目标应用启用状态,再执行原有的资源归属、版本、幂等、核查证据和审计规则。管理审计操作者为 `console:<user_id>`,操作归入目标命名空间。读取其他范围的资源 ID 不会越权返回数据。不存在的范围、未授权范围不自动回退。
缺少 Cookie 或会话失效返回 401;不允许的范围切换、混用 SDK Bearer、跨站写操作返回 403;目标应用停用或资源不属于当前范围返回 404。非法范围 ID 返回 400。页面切换采用完整导航,旧详情和请求不会在新应用页面呈现;URL 只保留非敏感 ID。
任务列表沿用原有 SQL 筛选语义:请求其他应用的队列会得到空列表;该队列或任务的单条详情返回 404。页面会先核对 URL 中的队列归属,错误队列不会被当成正常空列表。

View File

@@ -1,6 +1,6 @@
# 执行尝试与证据查询 v1 # 执行尝试与证据查询 v1
更新:2026-09-17。四个只读接口及独立 Go SDK 已实现;对应 [可运行示例](../../sdk/go/examples/history/main.go) 和 [回归记录](../reports/phase-2-execution-history.md)。 更新:2026-09-17。四个只读接口及独立 Go SDK 已实现;对应 [可运行示例](../../examples/history/main.go) 和 [回归记录](../reports/phase-2-execution-history.md)。
## 1. 用途与权限 ## 1. 用途与权限

View File

@@ -80,7 +80,7 @@ accepted, err := api.SubmitTask(ctx, "update-object-42-operation-001", orbit.Sub
## 5. 完整可运行场景 ## 5. 完整可运行场景
源码:[keyed-concurrency/main.go](../../sdk/go/examples/keyed-concurrency/main.go)。示例创建两个专用队列,每条队列提交一个相同资源键的任务;两个自动 Worker 各自容量为 4。处理器调用一个受控内存资源模型,查询尝试确认序号增长,最后模拟旧请求验证它被拒绝。 源码:[keyed-concurrency/main.go](../../examples/keyed-concurrency/main.go)。示例创建两个专用队列,每条队列提交一个相同资源键的任务;两个自动 Worker 各自容量为 4。处理器调用一个受控内存资源模型,查询尝试确认序号增长,最后模拟旧请求验证它被拒绝。
从仓库根目录,在专用开发数据库完成迁移并启动服务: 从仓库根目录,在专用开发数据库完成迁移并启动服务:
@@ -94,9 +94,9 @@ go run ./cmd/orbit
上述命令使用预先设置的 `ORBIT_MYSQL_DSN`,服务使用 `ORBIT_HTTP_ADDR=127.0.0.1:8080`。示例凭据需具有全部队列范围的 queues:manage、tasks:submit/read 和 workers:connect/consume。另一个终端执行: 上述命令使用预先设置的 `ORBIT_MYSQL_DSN`,服务使用 `ORBIT_HTTP_ADDR=127.0.0.1:8080`。示例凭据需具有全部队列范围的 queues:manage、tasks:submit/read 和 workers:connect/consume。另一个终端执行:
```sh ```sh
cd sdk/go cd examples
ORBIT_URL=http://127.0.0.1:8080 \ ORBIT_URL=http://127.0.0.1:8080 \
ORBIT_CREDENTIALS_FILE=/tmp/orbit-keyed.credentials.json go run ./examples/keyed-concurrency ORBIT_CREDENTIALS_FILE=/tmp/orbit-keyed.credentials.json go run ./keyed-concurrency
``` ```
正常输出: 正常输出:

View File

@@ -3,7 +3,7 @@
`orbit-admin release manifest` 不连接数据库,输出当前二进制内置的构建身份、协议版本和完整迁移名称/校验和。它用于在构建阶段冻结发布证据;输出不含 DSN、凭据、迁移 SQL 或业务数据。 `orbit-admin release manifest` 不连接数据库,输出当前二进制内置的构建身份、协议版本和完整迁移名称/校验和。它用于在构建阶段冻结发布证据;输出不含 DSN、凭据、迁移 SQL 或业务数据。
```sh ```sh
docker run --rm --entrypoint /usr/local/bin/orbit-admin registry.example/orbit:1.0.0 release manifest > orbit-release-manifest.json docker run --rm --entrypoint /usr/local/bin/orbit-admin registry.example/orbit:v0.1.1 release manifest > orbit-release-manifest.json
# 本地工作区也可执行: # 本地工作区也可执行:
make release-manifest > orbit-release-manifest.json make release-manifest > orbit-release-manifest.json
``` ```

View File

@@ -69,7 +69,7 @@ Worker 连接不再各自直接并发发起一批数据库领取。节点采用
## 4. SDK 完整场景 ## 4. SDK 完整场景
源码:[priority/main.go](../../sdk/go/examples/priority/main.go)。创建专用队列,先按 0、9、4 的顺序提交三条任务,再启动容量为 1 的自动 Worker;三条任务在近同时到期的条件下按 9、4、0 执行,每条只有一次尝试。 源码:[priority/main.go](../../examples/priority/main.go)。创建专用队列,先按 0、9、4 的顺序提交三条任务,再启动容量为 1 的自动 Worker;三条任务在近同时到期的条件下按 9、4、0 执行,每条只有一次尝试。
从仓库根目录准备专用开发数据库,设置 ORBIT_MYSQL_DSN 和 `ORBIT_HTTP_ADDR=127.0.0.1:8080` 后: 从仓库根目录准备专用开发数据库,设置 ORBIT_MYSQL_DSN 和 `ORBIT_HTTP_ADDR=127.0.0.1:8080` 后:
@@ -83,9 +83,9 @@ go run ./cmd/orbit
凭据需要全部队列范围的 queues:manage、tasks:submit/read、workers:connect/consume。另一个终端执行: 凭据需要全部队列范围的 queues:manage、tasks:submit/read、workers:connect/consume。另一个终端执行:
```sh ```sh
cd sdk/go cd examples
ORBIT_URL=http://127.0.0.1:8080 \ ORBIT_URL=http://127.0.0.1:8080 \
ORBIT_CREDENTIALS_FILE=/tmp/orbit-priority.credentials.json go run ./examples/priority ORBIT_CREDENTIALS_FILE=/tmp/orbit-priority.credentials.json go run ./priority
``` ```
预期输出: 预期输出:

View File

@@ -112,7 +112,7 @@ SDK 返回 `*orbit.APIError`,Code=QUEUE_FULL、StatusCode=429、RetryAfter=tim
## 完整 SDK 场景 ## 完整 SDK 场景
源码:[resources/main.go](../../sdk/go/examples/resources/main.go)。先完成当前迁移并启动服务,初始化带 Worker 权限且 queues:manage 范围为全部队列的专用开发凭据: 源码:[resources/main.go](../../examples/resources/main.go)。先完成当前迁移并启动服务,初始化带 Worker 权限且 queues:manage 范围为全部队列的专用开发凭据:
```sh ```sh
mkdir -p .local mkdir -p .local
@@ -120,10 +120,10 @@ chmod 700 .local
go run ./cmd/orbit-admin bootstrap \ go run ./cmd/orbit-admin bootstrap \
--application resources-demo --namespace default --environment development \ --application resources-demo --namespace default --environment development \
--queue bootstrap --worker-access --output .local/resources.credentials.json --queue bootstrap --worker-access --output .local/resources.credentials.json
cd sdk/go cd examples
ORBIT_URL=http://127.0.0.1:8080 \ ORBIT_URL=http://127.0.0.1:8080 \
ORBIT_CREDENTIALS_FILE=../../.local/resources.credentials.json \ ORBIT_CREDENTIALS_FILE=../.local/resources.credentials.json \
go run ./examples/resources go run ./resources
``` ```
示例创建独立队列(积压 2、并发 2、每秒 1 次开始),暂停后提交两个任务;第三个被拒,重复第一个仍得到原回执;取消第一个释放空间,用第三个原身份重新提交,然后恢复并执行两个纯数据回显任务。 示例创建独立队列(积压 2、并发 2、每秒 1 次开始),暂停后提交两个任务;第三个被拒,重复第一个仍得到原回执;取消第一个释放空间,用第三个原身份重新提交,然后恢复并执行两个纯数据回显任务。
@@ -145,3 +145,7 @@ unfinished=0 rate_per_second=1 worker_drained=true
创建命令省略新字段时,幂等摘要保留旧字段集合。旧创建回执不含新字段,SDK 解码为零,只表示历史快照缺少信息,实时配置另行 GetQueue。配置接口是新能力;自动 SDK 已能处理 RATE_LIMITED,进行降额管理前应先升级 Worker。 创建命令省略新字段时,幂等摘要保留旧字段集合。旧创建回执不含新字段,SDK 解码为零,只表示历史快照缺少信息,实时配置另行 GetQueue。配置接口是新能力;自动 SDK 已能处理 RATE_LIMITED,进行降额管理前应先升级 Worker。
本阶段验证见 [资源控制报告](../reports/phase-3-queue-resources.md)。[应用级跨命名空间配额](application-resources.md) 已实现并同时生效。[资源键许可](keyed-concurrency.md) 与 [优先级/节点公平派发](priority-and-fairness.md) 已实现;可靠事件积压限制及跨节点公平负载和容量验收继续推进。 本阶段验证见 [资源控制报告](../reports/phase-3-queue-resources.md)。[应用级跨命名空间配额](application-resources.md) 已实现并同时生效。[资源键许可](keyed-concurrency.md) 与 [优先级/节点公平派发](priority-and-fairness.md) 已实现;可靠事件积压限制及跨节点公平负载和容量验收继续推进。
## 永久退役
`POST /v1/queues/{id}:retire`,需要 `queues:manage`、原幂等键、`expected_revision` 和 `reason`。完整前置条件、错误和 SDK 用法见[通用资源退役](resource-retirement.md)。返回原 QueueResult,新增可空 `queue.retired_at`;暂停仍允许受理,退役禁止新工作。历史读取保持可用。

View File

@@ -0,0 +1,85 @@
# 通用资源退役
适用于长期服务、临时环境和自动化回归。平台不根据应用名称、队列名称或测试前缀自动清理。退役是不可恢复的显式管理动作,保留资源 ID、名称、任务、交付、幂等回执与审计;不是硬删除,也不自动归档或缩小数据库。
## 接口与权限
| 操作 | HTTP | 权限 | Go SDK |
| --- | --- | --- | --- |
| 退役订阅 | `POST /v1/subscriptions/{id}:retire` | `events:manage`,原凭据所有权和队列授权 | `RetireSubscription` |
| 退役队列 | `POST /v1/queues/{id}:retire` | `queues:manage` 和队列授权 | `RetireQueue` |
单管理员通过已登录的控制台管理授权范围;普通 SDK 不能操作其他凭据的订阅。请求需要 Bearer 身份及 `Idempotency-Key`,不接受查询参数,正文:
```json
{"expected_revision":"3","reason":"临时资源已结清,结束使用"}
```
成功 HTTP 200,保持现有 `request_id + data/error` 信封。data 分别为 `{subscription,deduplicated}`、`{queue,deduplicated}`。查询及列表增加可选 `retired_at`;订阅同时增加十进制字符串 `retired_sequence`。旧记录不需要回填。
同键同内容返回原回执,不因状态已经退役而失败;同键不同内容为 `IDEMPOTENCY_CONFLICT`。无明确回执时必须保存并重用原目标、请求和键,不自动生成新键。新命令须携带最新配置 revision。
## 订阅的结清边界
退役事务锁定命名空间结果流的已提交水位,再锁订阅。必须同时满足:
- pending_count=0,实际不存在 PENDING、LEASED 或 EXPIRED 交付。
- 截止水位之前,没有该队列和类型过滤范围内尚未物化的结果;缺失来源或历史保留缺口也拒绝退役。
成功后 enabled=false,记录退役水位并推进 cursor 至该水位,释放一个活动名额。此后新产生的事件不再属于该订阅。管理员应先停止旧生产者并排空消费者;平台无法判断调用方将来是否还会提交任务。
暂停依然占活动名额;每命名空间最多 64 个未退役订阅。已退役记录仍可列表、读取和查交付历史,不能恢复、重置起点或更换原名称。不存在通过忽略未消费事件强制释放名额的接口。
## 队列的依赖保护
队列退役按应用额度、操作身份、队列持锁,与提交、执行和流程推进串行。下列情况返回 `RESOURCE_BUSY` 并说明原因:
- 有未完成或待核查任务、在途执行尝试或未释放执行许可。
- 有启用的定时计划。先暂停计划,已产生任务仍须结清。
- 有固定版本引用该队列的未终结流程,包括暂停、等待、尚未执行到该队列的分支。
- 有未退役订阅,包括暂停订阅。
成功后 paused=true,禁止新任务、新订阅、Worker 注册、计划创建/发布/恢复以及使用该队列启动新流程。已发布流程定义和暂停计划作为历史保留,不能绕过退役恢复新工作。任务与流程历史查询继续可用,原已完成命令的冻结回执不重写。队列名称不回收,重新使用需创建新 ID 和名称。
## SDK 与自动化收尾
使用 `git.yuntuo.hk/k2safe/orbit/sdk/go@v0.1.2`;旧 v0.1.1 消费/提交协议继续兼容,但不包含新方法。当前仓库内可直接从 `sdk/go` 运行示例。
```go
sub, err := client.GetSubscription(ctx, subscriptionID)
if err != nil { return err }
// 实际服务应把 key 和请求持久保存,未知回执重放原内容。
retire := orbit.RetireResourceRequest{
ExpectedRevision: sub.Revision,
Reason: "临时资源已经结清",
}
_, err = client.RetireSubscription(ctx, subscriptionID, stableOperationKey, retire)
if err != nil { return err } // RESOURCE_BUSY 时先排空/核查,不能跳过结果。
queue, err := client.GetQueue(ctx, queueID)
if err != nil { return err }
_, err = client.RetireQueue(ctx, queueID, stableQueueOperationKey,
orbit.RetireResourceRequest{ExpectedRevision: queue.Revision, Reason: "停止使用队列"})
return err
```
建议顺序:停止生产者和计划 → 结清执行与流程 → 消费并确认所有订阅结果 → 退役订阅 → 退役队列。失败的测试可能保留待核查任务,收尾应报告资源 ID 与阻塞原因,不能把测试失败变成丢弃结果的理由。
完整可运行示例:[resource-lifecycle](../../sdk/go/examples/resource-lifecycle/README.md)。示例只操作本次新建空资源;进程异常终止仍可能留下资源,需要按输出 ID 核查,不能无限创建来绕过名额。
## 错误和管理页面
| HTTP / code | 含义 |
| --- | --- |
| 409 `RESOURCE_BUSY` | 尚未结清,message 给出依赖或积压原因;状态不变 |
| 409 `RESOURCE_RETIRED` | 新命令试图复用已退役资源 |
| 409 `STATE_CONFLICT` | 配置版本不匹配 |
| 409 `IDEMPOTENCY_CONFLICT` | 原键对应不同内容 |
| 410 `EVENT_HISTORY_EXPIRED` | 订阅存在无法验证的历史缺口 |
| 401 / 403 / 404 | 保持现有身份、权限和资源隔离语义 |
控制台“结果订阅”详情提供退役入口;“应用接入”提供所选队列退役和活动订阅名额。多队列时明确选择,浏览器只记忆命名空间对应的队列 ID;暂停/退役状态清晰展示。复制配置不会静默换成另一张凭据有权限的队列。
## 部署与保留
先停止旧写节点,再执行迁移 000034,再启动新版本;不要混跑不认识退役状态的旧服务端。现有资源默认未退役,不自动处理任何应用或测试数据。新库基线仍为零外键。历史保留、归档导出继续按现有配置执行;本次退役不引入自动删除机制。

View File

@@ -92,13 +92,13 @@ WorkerFailure 默认 Retryable=false;普通 error、panic、runtime.Goexit 和
## 5. 运行完整示例 ## 5. 运行完整示例
源码:[examples/retry/main.go](../../sdk/go/examples/retry/main.go)。先运行当前迁移、服务,并按 [Worker 初始化步骤](../sdk/worker.md#1-可运行的文本规范化示例) 准备具有提交、读取、消费权限的专用凭据。从仓库根目录执行: 源码:[examples/retry/main.go](../../examples/retry/main.go)。先运行当前迁移、服务,并按 [Worker 初始化步骤](../sdk/worker.md#1-可运行的文本规范化示例) 准备具有提交、读取、消费权限的专用凭据。从仓库根目录执行:
```sh ```sh
cd sdk/go cd examples
ORBIT_URL=http://127.0.0.1:8080 \ ORBIT_URL=http://127.0.0.1:8080 \
ORBIT_CREDENTIALS_FILE=../../.local/worker.credentials.json \ ORBIT_CREDENTIALS_FILE=../.local/worker.credentials.json \
go run ./examples/retry go run ./retry
``` ```
输入为 `{"text":" safe retry "}`。第一次处理在产生效果前模拟明确拒绝,第二次执行真正的文本规范化;重试等待由平台持久化安排。 输入为 `{"text":" safe retry "}`。第一次处理在产生效果前模拟明确拒绝,第二次执行真正的文本规范化;重试等待由平台持久化安排。

View File

@@ -178,13 +178,13 @@ go run ./cmd/orbit-admin bootstrap \
--application schedule-demo --namespace default --environment development \ --application schedule-demo --namespace default --environment development \
--queue snapshots --worker-access --schedule-access \ --queue snapshots --worker-access --schedule-access \
--output .local/schedule.credentials.json --output .local/schedule.credentials.json
cd sdk/go cd examples
ORBIT_URL=http://127.0.0.1:8080 \ ORBIT_URL=http://127.0.0.1:8080 \
ORBIT_CREDENTIALS_FILE=../../.local/schedule.credentials.json \ ORBIT_CREDENTIALS_FILE=../.local/schedule.credentials.json \
go run ./examples/schedules go run ./schedules
``` ```
前置数据库与目录步骤见 [SDK 接入](../sdk/README.md)。源码:[完整调度示例](../../sdk/go/examples/schedules/main.go)。示例创建暂停的每秒计划,恢复后让自动 Worker 返回对象输入快照,查询两次完成,再暂停并排空。计划本身有十秒结束边界,任务与历史保留;重复运行生成独立身份,不调用外部业务系统。 前置数据库与目录步骤见 [SDK 接入](../sdk/README.md)。源码:[完整调度示例](../../examples/schedules/main.go)。示例创建暂停的每秒计划,恢复后让自动 Worker 返回对象输入快照,查询两次完成,再暂停并排空。计划本身有十秒结束边界,任务与历史保留;重复运行生成独立身份,不调用外部业务系统。
```text ```text
source_kind=SCHEDULE fixed_version=1 source_kind=SCHEDULE fixed_version=1

View File

@@ -14,10 +14,11 @@
| GET /v1/subscriptions?queue_id=... | events:read | ListSubscriptions | | GET /v1/subscriptions?queue_id=... | events:read | ListSubscriptions |
| GET /v1/subscriptions/{id} | events:read | GetSubscription | | GET /v1/subscriptions/{id} | events:read | GetSubscription |
| POST /v1/subscriptions/{id}:configure | events:manage | ConfigureSubscription | | POST /v1/subscriptions/{id}:configure | events:manage | ConfigureSubscription |
| POST /v1/subscriptions/{id}:retire | events:manage | RetireSubscription |
| GET /v1/subscriptions/{id}/deliveries | events:read | ListEventDeliveries | | GET /v1/subscriptions/{id}/deliveries | events:read | ListEventDeliveries |
| GET /v1/subscriptions/{id}/deliveries/{delivery_id} | events:read | GetEventDelivery | | GET /v1/subscriptions/{id}/deliveries/{delivery_id} | events:read | GetEventDelivery |
| POST /v1/subscriptions/{id}/deliveries/{delivery_id}:retry | events:manage | RetryEventDelivery | | POST /v1/subscriptions/{id}/deliveries/{delivery_id}:retry | events:manage | RetryEventDelivery |
| GET /v1/events/connect(WebSocket Upgrade) | events:consume | 连接 SDK 待交付,可按下文协议接入 | | GET /v1/events/connect(WebSocket Upgrade) | events:consume | ConnectEvents / NewEventConsumer |
HTTP 使用统一 request_id + data/error 信封,响应带 X-Request-ID 和 Cache-Control: no-store。管理请求 8 秒服务端超时、JSON 最大 512 KiB。未知字段、大小写别名、重复 JSON 键、未知或重复查询参数均被拒绝。计数/版本以规范十进制字符串传输,不能带正号、前导零或小数。 HTTP 使用统一 request_id + data/error 信封,响应带 X-Request-ID 和 Cache-Control: no-store。管理请求 8 秒服务端超时、JSON 最大 512 KiB。未知字段、大小写别名、重复 JSON 键、未知或重复查询参数均被拒绝。计数/版本以规范十进制字符串传输,不能带正号、前导零或小数。
@@ -76,7 +77,7 @@ POST /v1/subscriptions,Content-Type: application/json,Idempotency-Key: 调
类型集合按固定顺序规范化。cursor_sequence 表示已经扫描并建立交付记录的位置,**不是确认水位**。pending_count 包含等待、租约中和次数耗尽记录。配置 revision 不随物化/ACK 用量变化。 类型集合按固定顺序规范化。cursor_sequence 表示已经扫描并建立交付记录的位置,**不是确认水位**。pending_count 包含等待、租约中和次数耗尽记录。配置 revision 不随物化/ACK 用量变化。
每命名空间最多 64 个订阅。from_sequence 不能超过已提交流头,也不能早于已清理的保留边界。现存日志从迁移 000013 启用,不补造此前的任务结果。 每命名空间最多 64 个未退役订阅;暂停仍占名额,成功退役后释放名额。from_sequence 不能超过已提交流头,也不能早于已清理的保留边界。现存日志从迁移 000013 启用,不补造此前的任务结果。
## 3. 查询和控制订阅 ## 3. 查询和控制订阅
@@ -291,7 +292,7 @@ snapshot 还可包含业务 result 和 current_attempt_id;result 用原始 JSO
| NOT_FOUND | 404;订阅/交付不在凭据与父资源范围;连接内发生时关闭 | | NOT_FOUND | 404;订阅/交付不在凭据与父资源范围;连接内发生时关闭 |
| STATE_CONFLICT | 409;版本、状态或累计预算不允许操作 | | STATE_CONFLICT | 409;版本、状态或累计预算不允许操作 |
| IDEMPOTENCY_CONFLICT | 409;同键内容不同 | | IDEMPOTENCY_CONFLICT | 409;同键内容不同 |
| SUBSCRIPTION_LIMIT | 409;命名空间订阅数达到 64 | | SUBSCRIPTION_LIMIT | 409;命名空间未退役订阅数达到 64 |
| EVENT_HISTORY_EXPIRED | 410;WSS 领取发现历史缺口则报错并关闭,不静默跳到最新位置 | | EVENT_HISTORY_EXPIRED | 410;WSS 领取发现历史缺口则报错并关闭,不静默跳到最新位置 |
| DELIVERY_LEASE_LOST | WSS ACK 证明已替换或无效;连接保留,等待新交付或核对历史 | | DELIVERY_LEASE_LOST | WSS ACK 证明已替换或无效;连接保留,等待新交付或核对历史 |
| PROTOCOL_REQUIRED | 升级前 426,必须指定 orbit.events.v1 | | PROTOCOL_REQUIRED | 升级前 426,必须指定 orbit.events.v1 |
@@ -322,6 +323,10 @@ _, err = client.ConfigureSubscription(ctx, current.ID, pauseKey, orbit.Configure
return err return err
``` ```
[完整管理示例](../../sdk/go/examples/subscriptions/main.go) 的启动、输入输出、失败和保留规则见 [场景文档](../examples/subscriptions.md)。它演示管理与幂等,不启动结果消费者。正式 [事件连接 SDK 与自动消费器](../sdk/event-consumer.md) 已提供接收、ACK、心跳、重连与有界收尾;[完整协议示例](../examples/event-protocol.md) 验证跨连接重报原确认。[独立 MySQL Inbox 示例](../examples/result-inbox.md) 已实现并验证消费者进程退出后的去重。 [完整管理示例](../../examples/subscriptions/main.go) 的启动、输入输出、失败和保留规则见 [场景文档](../examples/subscriptions.md)。它演示管理与幂等,不启动结果消费者。正式 [事件连接 SDK 与自动消费器](../sdk/event-consumer.md) 已提供接收、ACK、心跳、重连与有界收尾;[完整协议示例](../examples/event-protocol.md) 验证跨连接重报原确认。[独立 MySQL Inbox 示例](../examples/result-inbox.md) 已实现并验证消费者进程退出后的去重。
机器可读消息契约见 [events.schema.json](../../protocol/eventsv1/events.schema.json),使用 Draft 2020-12,clientFrame/serverFrame 分方向约束。运行时额外拒绝重复 JSON 键、超范围 uint64 及非规范 base64url。Schema 不代替授权、状态机、租约及事务校验。 机器可读消息契约见 [events.schema.json](../../protocol/eventsv1/events.schema.json),使用 Draft 2020-12,clientFrame/serverFrame 分方向约束。运行时额外拒绝重复 JSON 键、超范围 uint64 及非规范 base64url。Schema 不代替授权、状态机、租约及事务校验。
## 退役与资源名额
见[通用资源退役](resource-retirement.md)。退役保留订阅和交付历史,不支持重新启用;通过 `retired_at`、`retired_sequence` 区分暂停与退役。未确认、过期或尚未物化的匹配结果都会阻止退役。

View File

@@ -95,7 +95,7 @@ for {
} }
``` ```
片段假设已有客户端及time.Time类型from/before;完整可运行源码见[示例](../../sdk/go/examples/task-query/main.go)。SDK校验ID、范围、状态、键长度/UTF-8及时间精度,并用url.Values编码,时间转UTC,不修改调用方时间对象。超时只影响读取,可保持条件重新请求;没有自动重试或自动翻页。 片段假设已有客户端及time.Time类型from/before;完整可运行源码见[示例](../../examples/task-query/main.go)。SDK校验ID、范围、状态、键长度/UTF-8及时间精度,并用url.Values编码,时间转UTC,不修改调用方时间对象。超时只影响读取,可保持条件重新请求;没有自动重试或自动翻页。
## 5. 存储、升级与边界 ## 5. 存储、升级与边界

View File

@@ -132,10 +132,10 @@ SDK的ScheduleVersion为uint64,JSON仍为字符串;时间使用time.Time。S
| 场景 | 完整源码 | 运行说明与新增输出 | | 场景 | 完整源码 | 运行说明与新增输出 |
| --- | --- | --- | | --- | --- | --- |
| 单项受理、取消后读取来源 | [tasks](../../sdk/go/examples/tasks/main.go) | [SDK初始化](../sdk/README.md),source_kind=DIRECT | | 单项受理、取消后读取来源 | [tasks](../../examples/tasks/main.go) | [SDK初始化](../sdk/README.md),source_kind=DIRECT |
| 按计划找到触发任务,再反查来源 | [schedules](../../sdk/go/examples/schedules/main.go) | [计划场景](schedules.md#6-sdk-与完整示例),source_kind=SCHEDULE、fixed_version=1 | | 按计划找到触发任务,再反查来源 | [schedules](../../examples/schedules/main.go) | [计划场景](schedules.md#6-sdk-与完整示例),source_kind=SCHEDULE、fixed_version=1 |
| 人工核查后创建关联新任务 | [recovery](../../sdk/go/examples/recovery/main.go) | [恢复场景](../examples/recovery.md),source_kind=MANUAL_RETRY、parent=原任务ID | | 人工核查后创建关联新任务 | [recovery](../../examples/recovery/main.go) | [恢复场景](../examples/recovery.md),source_kind=MANUAL_RETRY、parent=原任务ID |
| 并行流程完成后核对每项任务来源 | [workflow](../../sdk/go/examples/workflow/main.go) | [流程场景](../examples/workflow.md),workflow_sources_verified=3、fixed_version=v1 | | 并行流程完成后核对每项任务来源 | [workflow](../../examples/workflow/main.go) | [流程场景](../examples/workflow.md),workflow_sources_verified=3、fixed_version=v1 |
上述示例均运行在隔离回归中;新发布计划/流程版本后老任务仍指向原版本,人工恢复后旧激活仍可追溯。WORKFLOW是新增来源种类,旧SDK可能按未知种类返回错误;应升级SDK,不能降级为DIRECT。不更改Task/TaskSummary或Worker消息结构,不增加权限配置;新客户端调用旧节点的404/503同样不能理解为DIRECT。 上述示例均运行在隔离回归中;新发布计划/流程版本后老任务仍指向原版本,人工恢复后旧激活仍可追溯。WORKFLOW是新增来源种类,旧SDK可能按未知种类返回错误;应升级SDK,不能降级为DIRECT。不更改Task/TaskSummary或Worker消息结构,不增加权限配置;新客户端调用旧节点的404/503同样不能理解为DIRECT。

View File

@@ -203,4 +203,4 @@ SDK:`Client.CancelTask(ctx, taskID, key, request)`。此操作不承诺回滚
{"request_id":"44444444444444444444444444444444","error":{"code":"IDEMPOTENCY_CONFLICT","message":"idempotency key was used with different content"}} {"request_id":"44444444444444444444444444444444","error":{"code":"IDEMPOTENCY_CONFLICT","message":"idempotency key was used with different content"}}
``` ```
有限自动重试已实现,具体分类、退避、回执和升级边界见 [安全重试](retries.md)。[运行中取消](cancellation.md) 已实现;[批量受理](batch-tasks.md) 已实现逐项结果与原身份补交;[独立任务核查与关联新任务重试](task-recovery.md) 已实现。[执行历史](execution-history.md) 已提供尝试与证据的列表和详情。完整可运行程序见 [SDK 任务示例](../../sdk/go/examples/tasks/main.go),已验证异常场景见 [P1 回归报告](../reports/phase-1.md) 及 [取消回归](../reports/phase-3-cancellation.md)。SDK 忽略未知响应字段;更改已有字段语义需升级契约和回归。 有限自动重试已实现,具体分类、退避、回执和升级边界见 [安全重试](retries.md)。[运行中取消](cancellation.md) 已实现;[批量受理](batch-tasks.md) 已实现逐项结果与原身份补交;[独立任务核查与关联新任务重试](task-recovery.md) 已实现。[执行历史](execution-history.md) 已提供尝试与证据的列表和详情。完整可运行程序见 [SDK 任务示例](../../examples/tasks/main.go),已验证异常场景见 [P1 回归报告](../reports/phase-1.md) 及 [取消回归](../reports/phase-3-cancellation.md)。SDK 忽略未知响应字段;更改已有字段语义需升级契约和回归。

View File

@@ -0,0 +1,65 @@
# 控制台登录保护
从 main 的数据库迁移 `000035` 开始启用。仅保护管理端账号密码登录,不改变业务 SDK Token、Worker 或结果订阅认证。保持单管理员,不引入角色管理系统。
## 默认行为
- 15 分钟失败窗口内连续失败 5 次,临时锁定 15 分钟。成功登录清空失败计数;失败窗口或锁定自然到期后重新计数。锁定期间尝试正确密码也不能登录,继续请求不会延长锁定。
- 同一账号每分钟最多受理 10 次,同一来源 IP 每分钟最多 30 次。固定窗口从首次尝试开始;成功登录不清空限流计数。任意一项触发就拒绝。
- 账号不存在、停用、密码错误或绑定凭据失效,正常拒绝均为 401。未知账号也参与相同限流/锁定,使用相同成本的 bcrypt 校验。既有账号按规范用户 ID 计数,避免等价 Unicode 登录名绕过限制。
- 触发锁定或限流返回 429,响应包含 `Retry-After` 秒数。登录页显示原因和倒计时;刷新页面不能绕过服务端限制。已登录会话不受一次新登录锁定影响,不中断业务服务。
- 数据库或审计提交失败返回 503,不签发 Cookie。跨站登录请求为 403;非法/过大的 JSON 为 400。
所有保护状态存放 MySQL,多节点共用,重启不归零。昂贵的密码校验在事务外执行:先用短事务占用请求预算,校验结束后再次锁定账号保护行;失败计数、锁定、成功会话和最终审计在同一事务提交。并发结果不能越过已经生效的账号锁定。校验进程异常退出的审计保留 PENDING,超过 10 分钟由清理器标 ERROR;不将未知结果当作密码错误。
## 部署配置
所有 Orbit 节点必须使用一致配置;不允许用 0 关闭保护。修改部署配置并重启服务后生效,不重置已有计数或已记录的锁定截止。降低阈值后按新阈值检查。
| 环境变量 | 默认值 | 约束 / 含义 |
| --- | --- | --- |
| `ORBIT_CONSOLE_LOGIN_FAILURE_LIMIT` | `5` | 1–100 次,触发临时锁定 |
| `ORBIT_CONSOLE_LOGIN_FAILURE_WINDOW` | `15m` | 1s–24h,连续失败窗口 |
| `ORBIT_CONSOLE_LOGIN_LOCK_DURATION` | `15m` | 1s–24h,新触发锁定时长 |
| `ORBIT_CONSOLE_LOGIN_ACCOUNT_LIMIT` | `10` | 1–1000 次 / 账号 / 限流窗口 |
| `ORBIT_CONSOLE_LOGIN_IP_LIMIT` | `30` | 1–10000 次 / IP / 限流窗口 |
| `ORBIT_CONSOLE_LOGIN_RATE_WINDOW` | `1m` | 1s–24h,固定限流窗口 |
| `ORBIT_CONSOLE_LOGIN_AUDIT_DAYS` | `90` | 1–3650 天,登录审计独立保留期 |
| `ORBIT_CONSOLE_TRUSTED_PROXIES` | 空 | 明确信任的代理 CIDR,逗号分隔 |
普通 Compose 和 HA Compose 均透传这些变量。本地测试环境在 `.local/compose-test/compose.env` 修改所需配置,再执行 `python3 scripts/orbit-local.py up`。此文件含其他私密配置,不提交仓库;不能仅在启动脚本外 export,脚本会隔离外部项目环境变量。
默认只使用 TCP 对端 IP,忽略客户端自带的 X-Forwarded-For、X-Real-IP。部署域名反向代理时,将实际代理的地址或精确网段填入 `ORBIT_CONSOLE_TRUSTED_PROXIES`,例如同机代理 `127.0.0.1/32,::1/128`。只在直连对端可信时解析 X-Forwarded-For,从右向左剥离可信代理;遇到第一个非可信地址停止。格式非法或跳数过多时退回 TCP 对端。代理应覆盖或按可信链追加转发头,不能把所有互联网地址都配置为受信代理。未配置时所有经代理的请求共用代理 IP 配额,账号维度仍独立生效。
## 查看审计
管理端右上角“登录审计”,仅部署指定的 `ORBIT_CONSOLE_APPLICATION_ADMIN` 可查看,默认每页 10 条。显示时间、登录名、来源 IP、结果和可重试时间;记录用户名不代表该账号一定存在。SDK Bearer、未登录或普通控制台账号无权读取全局记录。
接口:`GET /console/auth/audit?before=<上页next>`,认证为有效 HttpOnly 管理员会话 Cookie。响应:
```json
{"data":{"items":[{"id":"42","username":"operator","remote_ip":"192.0.2.1","user_agent":"browser","outcome":"LOCKED","created_at":"2026-09-29T12:00:00Z","finished_at":"2026-09-29T12:00:00Z","retry_at":"2026-09-29T12:15:00Z"}],"next":"42"}}
```
`next` 仅在还有下一页时提供,是倒序分页的排他上界;无全库计数、不承诺跨页快照。结果类型:SUCCESS、INVALID、LOCKED、ACCOUNT_LIMIT、IP_LIMIT、PENDING、ERROR。审计从不保存密码、Cookie、Token 或这些秘密的摘要,浏览器列表不会自动拉取接入 Token。
登录拒绝示例:
```http
HTTP/1.1 429 Too Many Requests
Retry-After: 900
Cache-Control: no-store
Content-Type: application/json
```
限流代码为 `LOGIN_RATE_LIMITED`。不要让客户端自动循环重试账号密码登录。
## 保留与升级
迁移只新增 `orbit_console_login_guards` 与 `orbit_console_login_audit`,无外键,不更改已有用户、密码、会话、凭据及业务记录。先备份,停止旧节点,再前向迁移和统一部署;旧版没有保护,不能和新版混跑。
每分钟清理一次,每种语句最多处理 500 行:48 小时未更新的保护状态、超过配置天数的登录审计,以及超时 PENDING 的状态归类。有效保护窗口最长 24 小时,48 小时非活动清理不会提前解除有效锁定。清理有索引、有截止时间,失败保留记录并写错误日志;这不会缩小数据库已分配磁盘,也不替代备份。业务“保留策略”管理的是命名空间历史,登录审计的全局保留时间由上述独立配置管理。
锁定自然到期后使用正确密码登录即可;不自动改密码、撤销业务 Token 或踢出已有会话。若持续遭受攻击,管理员应按审计中的来源限制访问并核对反向代理配置,不能通过关闭计数绕过保护。
锁定自然到期后使用正确密码登录即可;不自动改密码、撤销业务 Token 或踢出已有会话。若持续遭受攻击,管理员应按审计中的来源限制访问并核对反向代理配置,不能通过关闭计数绕过保护。

View File

@@ -1,6 +1,6 @@
# Orbit Console · 星轨控制台 # Orbit Console · 星轨控制台
Orbit 内置了一个不依赖 Node.js、外部 CDN 或额外文件挂载的管理控制台第一版。静态资源编译进 Orbit 二进制,入口为: Orbit 内置了一个不依赖 Node.js、外部 CDN 或额外文件挂载的管理控制台。静态资源编译进 Orbit 二进制,入口为:
```text ```text
http://127.0.0.1:8080/console/ http://127.0.0.1:8080/console/
@@ -8,10 +8,10 @@ http://127.0.0.1:8080/console/
## 当前能力 ## 当前能力
- 读取 `/health/live`、`/health/ready` 和 `/version` 展示服务、Schema 与工具链状态。 - 读取 `/health/ready` 和 `/version` 展示服务就绪状态及版本;数据库未就绪时明确提示不可用。
- 通过数据库中的控制台账号登录;服务端使用 HttpOnly 会话 Cookie 调用现有授权 API,浏览器不接触业务 Token。 - 通过数据库中的控制台账号登录;服务端使用 HttpOnly 会话 Cookie 调用现有授权 API,普通业务页面无需业务 Token;应用接入页仅在管理员明确查看时读取当前 Token。
- 总览页直接展示当前查询窗口的任务成功率、任务状态分布、活跃计划、待核查流程和待交付结果;登录和权限信息不会占用统计区域。 - 总览展示各类最近 20 条记录的快照:任务成功占比、状态分布、启用计划、待核查流程和待确认结果,并提供异常入口与最近任务。已取消单独统计,不算失败;快照不是全库累计。
- 展示任务、定时计划、流程实例和结果订阅的最近摘要。 - 页顶选择应用、环境与队列;任务、计划、流程、订阅、归档列表和详情显示应用归属。应用和队列范围保存在 URL,重新打开、复制链接及后退可恢复;列表条件和页码在当前页面会话内保持。
- 点击任务查看任务详情、执行尝试时间线、最终结果和操作审计摘要。 - 点击任务查看任务详情、执行尝试时间线、最终结果和操作审计摘要。
- 在具备对应权限时提交任务取消和安全重试,沿用服务端的版本校验、幂等键、队列范围和审计规则。 - 在具备对应权限时提交任务取消和安全重试,沿用服务端的版本校验、幂等键、队列范围和审计规则。
- 点击定时计划查看当前版本、规则、下一次触发和触发记录;在具备 `schedules:manage` 权限时可暂停或恢复计划。 - 点击定时计划查看当前版本、规则、下一次触发和触发记录;在具备 `schedules:manage` 权限时可暂停或恢复计划。
@@ -20,17 +20,18 @@ http://127.0.0.1:8080/console/
- 在具备 `workflows:control` 权限时,流程详情可以暂停、恢复或取消;操作原因、`control_revision` 和幂等键交给服务端做最终校验。 - 在具备 `workflows:control` 权限时,流程详情可以暂停、恢复或取消;操作原因、`control_revision` 和幂等键交给服务端做最终校验。
- `NEEDS_REVIEW` 流程会显示按步骤类型划分的人工恢复入口:任务核查、步骤结论、继续、步骤重试、PENDING 接续和等待重建;每次提交都要求当前修订、证据引用和显式确认,服务端恢复 API 负责最终门控。 - `NEEDS_REVIEW` 流程会显示按步骤类型划分的人工恢复入口:任务核查、步骤结论、继续、步骤重试、PENDING 接续和等待重建;每次提交都要求当前修订、证据引用和显式确认,服务端恢复 API 负责最终门控。
- 在具备 `events:manage` 权限时,订阅详情可以启停订阅,并对 `EXPIRED` 交付追加次数预算后重试;原交付身份、已用次数和事件不会被页面重置。 - 在具备 `events:manage` 权限时,订阅详情可以启停订阅,并对 `EXPIRED` 交付追加次数预算后重试;原交付身份、已用次数和事件不会被页面重置。
- 左侧六个模块是独立的控制台视图,使用 `/console/#/overview`、`#/tasks`、`#/schedules`、`#/workflows`、`#/subscriptions` 和 `#/retention` 定位;切换视图不会把所有模块堆在一张长页面上。 - 工作台固定导航和页头,内容区独立滚动;切换模块回到内容顶部。应用详情相同快照不重建,后台刷新会避让正在滚动、编辑或展开详情的操作。
- 左侧八个模块是独立视图:总览、任务、计划、流程、订阅、保留策略、归档作业和应用接入。
- “保留策略”只允许单管理员查看和修改命名空间级窗口;修改需要版本号、幂等键和原因并留下审计。预览和只读导出不会删除源数据,未确认交付、未知效果和未结束流程不会成为候选。 - “保留策略”只允许单管理员查看和修改命名空间级窗口;修改需要版本号、幂等键和原因并留下审计。预览和只读导出不会删除源数据,未确认交付、未知效果和未结束流程不会成为候选。
- 任务状态按 10 秒自动刷新;页面只调用服务端授权接口,不把账号密码或业务凭据上传到独立服务,也不读取数据库。 - 当前视图按 10 秒自动刷新,可在页顶暂停;输入、打开详情或操作弹窗时不自动重载。页面只调用服务端授权接口,不把账号密码或业务凭据上传到独立服务,也不读取数据库。
- 页面使用当前请求方的业务权限;没有权限的模块显示为空或等待权限,不绕过服务端授权。 - 普通账号沿用绑定凭据范围;部署指定管理员可显式选择应用环境管理。读取失败显示错误,避免当作空列表。
## 本地打开 ## 本地打开
启动 Orbit 后访问 `/console/`。未登录时,任何控制台业务页面都会跳转到 `/console/login`;登录成功后进入控制台,登录会话过期或服务端返回 401 时也会重新跳转。当前 Docker 开发环境入口: 启动 Orbit 后访问 `/console/`。未登录时,任何控制台业务页面都会跳转到 `/console/login`;登录成功后进入控制台,登录会话过期或服务端返回 401 时也会重新跳转。使用 `scripts/orbit-local.py up` 部署的持久本地联调入口(通用 Compose 默认端口仍为 8080):
```text ```text
http://127.0.0.1:8080/console/ http://127.0.0.1:18080/console/
``` ```
首次使用可以在 `orbit-admin bootstrap` 时一起创建控制台管理员。这样业务资源、业务凭据和管理员账号在同一个初始化事务中提交: 首次使用可以在 `orbit-admin bootstrap` 时一起创建控制台管理员。这样业务资源、业务凭据和管理员账号在同一个初始化事务中提交:
@@ -48,7 +49,7 @@ secret-manager read orbit/console-admin-password | \
--output .local/production.credentials.json --output .local/production.credentials.json
``` ```
密码不会进入命令参数、日志或 JSON 文件,初始化失败时资源和账号一起回滚。已经完成业务初始化的环境,也可以由数据库管理员单独创建控制台账号。账号绑定一个已有的命名空间凭据,账号权限就是该凭据的权限;这不会轮换或输出业务 Token。推荐从私有凭据文件读取命名空间和凭据标识,并从标准输入交付密码: 密码不会进入命令参数、日志或 JSON 文件,初始化失败时资源和账号一起回滚。已经完成业务初始化的环境,也可以由数据库管理员单独创建控制台账号。账号绑定一个已有的命名空间凭据,未指定为应用管理员的账号沿用该凭据权限;这不会轮换或输出业务 Token。推荐从私有凭据文件读取命名空间和凭据标识,并从标准输入交付密码:
```sh ```sh
./bin/orbit-admin console-user create \ ./bin/orbit-admin console-user create \
@@ -74,6 +75,38 @@ export ORBIT_CONSOLE_QUEUE_ID='queue_xxx'
## 安全边界 ## 安全边界
控制台不直接访问数据库,也不绕过业务凭据权限。登录会话只保存令牌摘要,服务端每次请求都会校验账号、会话、命名空间、应用启停和凭据权限。取消和人工重试会使用当前任务版本生成一次性幂等键;网络结果不明时不要重复点击,应使用原始操作身份通过 API/SDK 核对。`NEEDS_REVIEW` 任务仍须使用带证据的核查 API/SDK 完成最终裁决。控制台账号绑定业务凭据,不自动获得跨命名空间权限;不支持跨命名空间聚合,不代替平台的权限与审计 API。 登录已具备持久化失败计数、临时锁定、账号/IP 限流和单管理员登录审计。默认 15 分钟内连续失败 5 次锁定 15 分钟,账号/IP 每分钟分别最多尝试 10/30 次;阈值、窗口、审计保留期和可信代理均可配置。页面显示 429 原因及倒计时,服务重启不清空保护状态。配置与接口见[登录保护](console-login-security.md)。
控制台通过服务端授权访问数据库。登录会话只保存令牌摘要,服务端每次请求都会校验账号、会话、命名空间、应用启停和凭据权限。取消和人工重试会使用当前任务版本生成一次性幂等键;网络结果不明时不要重复点击,应使用原始操作身份通过 API/SDK 核对。`NEEDS_REVIEW` 任务仍须使用带证据的核查 API/SDK 完成最终裁决。普通账号不自动获得跨命名空间权限;部署指定的单管理员可显式选择应用范围,每个业务事务重新核验原会话及目标应用。各应用分别展示,SDK 权限不变。
不能把业务 Token 长期放进浏览器本地存储,也不能让控制台直连 MySQL。计划版本发布、跨命名空间管理身份和其他高风险写操作仍应通过受保护 API/SDK 设计后再接入页面。流程恢复入口只调用已经定义的恢复 API,不自动猜测结果、不替操作者补齐证据,也不把冲突重试成“最新版本”。 不能把业务 Token 长期放进浏览器本地存储,也不能让控制台直连 MySQL。计划版本发布、跨命名空间管理身份和其他高风险写操作仍应通过受保护 API/SDK 设计后再接入页面。流程恢复入口只调用已经定义的恢复 API,不自动猜测结果、不替操作者补齐证据,也不把冲突重试成“最新版本”。
## 应用接入
侧栏「应用接入」提供应用创建、队列与凭据查看、Token 重新生成和完整 SDK 配置交付。配置 `ORBIT_CONSOLE_APPLICATION_ADMIN=admin` 指定唯一管理登录名,并配置 `ORBIT_CREDENTIAL_KEY_FILE` 保管密钥;本地 Compose 自动配置。可随时查看、复制当前完整接入信息。业务页面支持该管理员选择应用范围,订阅原 SDK 凭据绑定不变。[功能、接口、权限和恢复说明](api/console-applications.md)。
## 按应用查看数据
页顶「应用 / 环境」选择已创建的应用,再选择队列。两处下拉菜单支持搜索已加载的选项,应用名称和环境分行展示;支持方向键、Enter 选择及 Escape 关闭。任务、定时计划和结果订阅按队列读取;流程、保留策略和归档按应用环境所属命名空间读取,页面有范围提示。应用每页 50 项、队列每页 100 项,选择「加载更多…」获取下一页。没有队列的应用仍能查看流程和归档。
切换采用完整导航,隔离旧请求和详情;有未保存策略、未确认操作或打开的详情时需先处理完。URL 只保存非敏感 ID。无效范围显示错误,不降级读取默认应用。总览仍是最近查询窗口的统计,不是全库累计。
只有部署指定管理员可以切换应用;其他账号只展示自己的应用和授权队列。后台停用应用、撤销绑定凭据或退出账号后,原页面范围不能继续授予权限。[范围接口及授权规则](api/console-scope.md)。
## 资源退役与明确接入目标
应用接入页按命名空间记忆所选队列;多队列且没有记忆时要求明确选择,不根据名称猜测业务用途。下拉框显示暂停/退役状态,已退役队列不能导出成新接入配置;凭据无该队列权限时直接提示,不自动换目标。
结果订阅详情和应用接入页分别提供订阅、队列退役;每次提交需要原因和当前版本,网络不明确时保留原键重报。活动订阅名额包含暂停订阅,退役后释放,历史仍可查询;阻塞原因明确显示。未补存当前 Token 时,预览入口与过渡提示都要求先补存,避免误认为已有可复制的新配置。
## 查询与日常操作
1. 在页顶选择应用环境;任务、计划、订阅再选择队列。
2. 任务与流程可组合状态、完整业务键和创建时间查询。业务键精确匹配,保留大小写、特殊字符和尾部空格;时间输入按浏览器时区换算,开始包含、结束不包含。
3. 四个资源列表默认每页 10 条,可选择 10 / 20 / 50 / 100 条、下一页、上一页和回到最新。请求服务端游标,不在前端截取全部数据。自动刷新和手动「刷新数据」保留当前条件及页码;改变条件或页大小回到第一页。分页期间数据可能继续变化,不承诺固定快照。
4. 在页面右上输入完整 32 位资源 ID 可直接定位;详情可复制完整 ID。读取失败保留筛选并提示原因,迟到的旧查询不会覆盖新查询。详情打开后焦点留在抽屉内,Escape 关闭后回到原入口。
5. 应用接入页可搜索本页应用,先选择接入队列,再查看或复制完整配置。应用标识、权限、有效期调整、退役等低频信息折叠展示;查看与换证沿用原有身份、权限和审计规则。
全站采用浅色工作台和统一表格。窄屏导航可横向滑动,宽表格在自身容器中滚动;登录页与控制台使用相同视觉样式。
前端校验运行 `make console-check`(开发机需要 Node.js,运行服务无需 Node.js);真实 MySQL、登录保护、任务执行与控制台接口链路运行 `make console-e2e`。本批范围与浏览器验收见[管理端改版记录](reports/console-refresh.md)。

View File

@@ -1,16 +1,18 @@
# 通用场景示例 # 通用场景示例
完整源码已统一放在根目录 [examples/](../../examples/README.md),共有 27 个可运行场景;各目录 README 提供命令和预期结果。首次接入先看[仓库 README](../../README.md)。
示例只使用通用的作业、对象、文件、资源与审核信号,不包含接入方项目名称或行业规则。 示例只使用通用的作业、对象、文件、资源与审核信号,不包含接入方项目名称或行业规则。
## 已可运行:研发定义与发布流程 ## 已可运行:研发定义与发布流程
- [完整命令和结果](workflow-definition.md)、[SDK源码](../../sdk/go/examples/workflow-definition/main.go)。 - [完整命令和结果](workflow-definition.md)、[SDK源码](../../examples/workflow-definition/main.go)。
- 六类节点的有限结构定义、原键及同版本确认、新版本发布、旧版本读取保持不变。 - 六类节点的有限结构定义、原键及同版本确认、新版本发布、旧版本读取保持不变。
- 本例只发布定义;实际运行见下方流程示例。 - 本例只发布定义;实际运行见下方流程示例。
## 已可运行:并行作业、定时等待与外部回执 ## 已可运行:并行作业、定时等待与外部回执
- [完整命令、输入输出与失败处理](workflow.md)、[独立SDK源码](../../sdk/go/examples/workflow/main.go)。 - [完整命令、输入输出与失败处理](workflow.md)、[独立SDK源码](../../examples/workflow/main.go)。
- 两个任务并行处理并汇合,计时等待后接收显式目标代次的信号,再执行后续任务;最终三个任务完成并有界排空。 - 两个任务并行处理并汇合,计时等待后接收显式目标代次的信号,再执行后续任务;最终三个任务完成并有界排空。
- 启动及信号原键重复不会建立新的实例或信号;分页查看原状态事件,核对信号消费及赢家等待。 - 启动及信号原键重复不会建立新的实例或信号;分页查看原状态事件,核对信号消费及赢家等待。
@@ -32,13 +34,13 @@
## 已可运行:相对延迟执行 ## 已可运行:相对延迟执行
- [完整命令、输入输出和失败处理](delayed-task.md),[SDK源码](../../sdk/go/examples/delayed-task/main.go)。 - [完整命令、输入输出和失败处理](delayed-task.md),[SDK源码](../../examples/delayed-task/main.go)。
- delay_ms按数据库首次受理时间计时,实际Worker执行后查询开始时间;重报原请求仍返回原任务及时间。 - delay_ms按数据库首次受理时间计时,实际Worker执行后查询开始时间;重报原请求仍返回原任务及时间。
- 自动失败重试单独使用retry策略,初始延迟不在每次尝试中重新计时。 - 自动失败重试单独使用retry策略,初始延迟不在每次尝试中重新计时。
## 已可运行:健康检查 ## 已可运行:健康检查
- 源码:[SDK 健康检查](../../sdk/go/examples/health/main.go)。 - 源码:[SDK 健康检查](../../examples/health/main.go)。
- 前置:已迁移的 MySQL 与已启动的基础服务。 - 前置:已迁移的 MySQL 与已启动的基础服务。
- 操作与预期输出:[SDK 接入说明](../sdk/README.md)。 - 操作与预期输出:[SDK 接入说明](../sdk/README.md)。
- 异常:数据库不可用或迁移记录异常时 readiness 返回 HTTP 503,SDK 返回类型化状态错误。 - 异常:数据库不可用或迁移记录异常时 readiness 返回 HTTP 503,SDK 返回类型化状态错误。
@@ -46,7 +48,7 @@
## 已可运行:文件转换任务的受理与取消 ## 已可运行:文件转换任务的受理与取消
- 源码:[SDK 任务受理示例](../../sdk/go/examples/tasks/main.go)。 - 源码:[SDK 任务受理示例](../../examples/tasks/main.go)。
- 前置:完成迁移、初始化凭据、启动服务,在没有 Worker 消费的专用队列运行此受理/取消示例,详见 [SDK 接入](../sdk/README.md)。 - 前置:完成迁移、初始化凭据、启动服务,在没有 Worker 消费的专用队列运行此受理/取消示例,详见 [SDK 接入](../sdk/README.md)。
- 输入:对象引用、格式与精确整数;提交两次同一身份,再查询、分页并带版本取消。 - 输入:对象引用、格式与精确整数;提交两次同一身份,再查询、分页并带版本取消。
- 预期:重复请求返回同一任务,最终 CANCELLED/revision=2,source_kind=DIRECT。当前不启动 Worker,不实际生成文件。 - 预期:重复请求返回同一任务,最终 CANCELLED/revision=2,source_kind=DIRECT。当前不启动 Worker,不实际生成文件。
@@ -55,7 +57,7 @@
## 已可运行:文件格式转换执行 ## 已可运行:文件格式转换执行
- 源码:[CSV→JSON Worker 示例](../../sdk/go/examples/file-conversion/main.go),[完整说明](file-conversion.md)。 - 源码:[CSV→JSON Worker 示例](../../examples/file-conversion/main.go),[完整说明](file-conversion.md)。
- 前置:专用 Worker 凭据、已启动服务和当前迁移;标准隔离回归会自动运行本例。 - 前置:专用 Worker 凭据、已启动服务和当前迁移;标准隔离回归会自动运行本例。
- 输入与步骤:提交带稳定操作键的两行 CSV 快照 → Worker 注册 `file.convert.csv-json` v1 → 领取、授权并转换 → 查询 JSON 结果 → 排空。 - 输入与步骤:提交带稳定操作键的两行 CSV 快照 → Worker 注册 `file.convert.csv-json` v1 → 领取、授权并转换 → 查询 JSON 结果 → 排空。
- 预期:`SUCCEEDED`、一次尝试、`records.json`、`rows=2`,重复提交仍沿用原任务身份。 - 预期:`SUCCEEDED`、一次尝试、`records.json`、`rows=2`,重复提交仍沿用原任务身份。
@@ -63,7 +65,7 @@
## 已可运行:文本规范化执行 ## 已可运行:文本规范化执行
- 源码:[Worker 底层协议示例](../../sdk/go/examples/worker-protocol/main.go)。 - 源码:[Worker 底层协议示例](../../examples/worker-protocol/main.go)。
- 前置:专用 Worker 凭据,启动步骤见 [Worker SDK 文档](../sdk/worker.md)。 - 前置:专用 Worker 凭据,启动步骤见 [Worker SDK 文档](../sdk/worker.md)。
- 输入与步骤:提交 `{"text":" Hello Orbit "}` → 注册/容量 → 领取 → 开始授权 → 实际处理 → 确认结果 → 查询 → 排空。 - 输入与步骤:提交 `{"text":" Hello Orbit "}` → 注册/容量 → 领取 → 开始授权 → 实际处理 → 确认结果 → 查询 → 排空。
- 预期:SUCCEEDED、一次尝试、结果 `{"text":"HELLO ORBIT"}`。 - 预期:SUCCEEDED、一次尝试、结果 `{"text":"HELLO ORBIT"}`。
@@ -72,7 +74,7 @@
## 已可运行:自动 Worker 并发消费 ## 已可运行:自动 Worker 并发消费
- 源码:[自动 Worker 示例](../../sdk/go/examples/worker/main.go),[接入与启动命令](../sdk/worker-runtime.md)。 - 源码:[自动 Worker 示例](../../examples/worker/main.go),[接入与启动命令](../sdk/worker-runtime.md)。
- 步骤:注册版本化处理器 → Run → 以容量 2 消费三条文本任务 → 查询结果 → 取消 Run context 并等待排空。 - 步骤:注册版本化处理器 → Run → 以容量 2 消费三条文本任务 → 查询结果 → 取消 Run context 并等待排空。
- 预期:三条规范化结果、started=3、confirmed=3、running=0;输入与结果均由实际代码处理。 - 预期:三条规范化结果、started=3、confirmed=3、running=0;输入与结果均由实际代码处理。
- 异常:自动心跳/续租与原身份重连;普通错误/panic 按未知效果报告,超时退出不声称杀死 goroutine;完整故障证据见 [回归记录](../reports/phase-2-worker-runtime.md)。 - 异常:自动心跳/续租与原身份重连;普通错误/panic 按未知效果报告,超时退出不声称杀死 goroutine;完整故障证据见 [回归记录](../reports/phase-2-worker-runtime.md)。
@@ -80,7 +82,7 @@
## 已可运行:执行历史与冲突证据核对 ## 已可运行:执行历史与冲突证据核对
- 源码:[执行历史示例](../../sdk/go/examples/history/main.go),[启动命令和输入输出](../sdk/README.md#6-查询执行历史与证据)。 - 源码:[执行历史示例](../../examples/history/main.go),[启动命令和输入输出](../sdk/README.md#6-查询执行历史与证据)。
- 前置:迁移到当前版本、启动服务,专用凭据具备提交/读取与 Worker 权限。 - 前置:迁移到当前版本、启动服务,专用凭据具备提交/读取与 Worker 权限。
- 步骤:创建模拟任务 → 开始授权 → 保存 v1 结果 → 用另一消息身份报告 v2 → 查询尝试/证据列表与详情 → 核对任务仍保留 v1。 - 步骤:创建模拟任务 → 开始授权 → 保存 v1 结果 → 用另一消息身份报告 v2 → 查询尝试/证据列表与详情 → 核对任务仍保留 v1。
- 预期:SUCCEEDED、attempts=1、evidence=1、reason=RESULT_CONFLICT、disposition=EVIDENCE_ONLY;实际结果中的大整数保持精确。 - 预期:SUCCEEDED、attempts=1、evidence=1、reason=RESULT_CONFLICT、disposition=EVIDENCE_ONLY;实际结果中的大整数保持精确。
@@ -89,7 +91,7 @@
## 已可运行:有限安全重试 ## 已可运行:有限安全重试
- 源码:[重试示例](../../sdk/go/examples/retry/main.go),[完整启动命令与结果](../api/retries.md#5-运行完整示例)。 - 源码:[重试示例](../../examples/retry/main.go),[完整启动命令与结果](../api/retries.md#5-运行完整示例)。
- 前置:当前迁移及服务,具有提交、读取和 Worker 权限的专用凭据。 - 前置:当前迁移及服务,具有提交、读取和 Worker 权限的专用凭据。
- 步骤:第一次在产生效果前模拟明确拒绝 → 平台持久化退避 → 第二次处理文本 → 查询两次尝试 → 排空。 - 步骤:第一次在产生效果前模拟明确拒绝 → 平台持久化退避 → 第二次处理文本 → 查询两次尝试 → 排空。
- 预期:SUCCEEDED、attempts=2、first_retryable=true、结果 `{"text":"SAFE RETRY"}`;Worker started=2、confirmed=2、running=0。 - 预期:SUCCEEDED、attempts=2、first_retryable=true、结果 `{"text":"SAFE RETRY"}`;Worker started=2、confirmed=2、running=0。
@@ -98,7 +100,7 @@
## 已可运行:周期对象快照 ## 已可运行:周期对象快照
- 源码:[调度示例](../../sdk/go/examples/schedules/main.go),[初始化、调用与输出](../api/schedules.md#6-sdk-与完整示例)。 - 源码:[调度示例](../../examples/schedules/main.go),[初始化、调用与输出](../api/schedules.md#6-sdk-与完整示例)。
- 前置:当前迁移、服务,显式 --schedule-access 与 --worker-access 的专用开发凭据。 - 前置:当前迁移、服务,显式 --schedule-access 与 --worker-access 的专用开发凭据。
- 步骤:创建暂停的有限每秒计划 → 恢复 → 自动 Worker 返回输入快照 → 查到至少两次任务成功 → 暂停并排空。 - 步骤:创建暂停的有限每秒计划 → 恢复 → 自动 Worker 返回输入快照 → 查到至少两次任务成功 → 暂停并排空。
- 预期:不同 occurrence/task 身份、相同计划版本、paused=true、running=0;精确整数保留。 - 预期:不同 occurrence/task 身份、相同计划版本、paused=true、running=0;精确整数保留。
@@ -107,7 +109,7 @@
## 已可运行:运行中任务取消 ## 已可运行:运行中任务取消
- 源码:[取消示例](../../sdk/go/examples/cancellation/main.go),[初始化、调用与输出](../api/cancellation.md)。 - 源码:[取消示例](../../examples/cancellation/main.go),[初始化、调用与输出](../api/cancellation.md)。
- 前置:当前迁移、全部服务节点升级完成,凭据具备任务提交/读取/取消和 Worker 权限。 - 前置:当前迁移、全部服务节点升级完成,凭据具备任务提交/读取/取消和 Worker 权限。
- 步骤:提交并开始受控任务 → 保存取消意图 → 处理器遵守 context 停止 → 明确确认本次无未结清效果 → 查询最终状态并排空。 - 步骤:提交并开始受控任务 → 保存取消意图 → 处理器遵守 context 停止 → 明确确认本次无未结清效果 → 查询最终状态并排空。
- 预期:accepted_state=RUNNING、final_state=CANCELLED、attempts=1、running=0。 - 预期:accepted_state=RUNNING、final_state=CANCELLED、attempts=1、running=0。
@@ -116,7 +118,7 @@
## 已可运行:队列限速与积压背压 ## 已可运行:队列限速与积压背压
- 源码:[资源控制示例](../../sdk/go/examples/resources/main.go),[初始化、字段与完整输出](../api/queues.md)。 - 源码:[资源控制示例](../../examples/resources/main.go),[初始化、字段与完整输出](../api/queues.md)。
- 前置:当前迁移与服务,凭据具备全部队列的 queues:manage、任务及 Worker 权限。 - 前置:当前迁移与服务,凭据具备全部队列的 queues:manage、任务及 Worker 权限。
- 步骤:创建并暂停积压上限为 2 的队列 → 第三个任务被 429 拒绝 → 满额下核对第一条原回执 → 取消释放空间 → 用被拒原身份再提交 → 恢复并按每秒 1 次开始执行。 - 步骤:创建并暂停积压上限为 2 的队列 → 第三个任务被 429 拒绝 → 满额下核对第一条原回执 → 取消释放空间 → 用被拒原身份再提交 → 恢复并按每秒 1 次开始执行。
- 预期:QUEUE_FULL、duplicate=true、两个任务 SUCCEEDED/attempts=1、unfinished=0。 - 预期:QUEUE_FULL、duplicate=true、两个任务 SUCCEEDED/attempts=1、unfinished=0。
@@ -125,7 +127,7 @@
## 已可运行:跨命名空间共享配额 ## 已可运行:跨命名空间共享配额
- 源码:[应用资源示例](../../sdk/go/examples/application-resources/main.go),[双命名空间初始化、字段和输出](../api/application-resources.md)。 - 源码:[应用资源示例](../../examples/application-resources/main.go),[双命名空间初始化、字段和输出](../api/application-resources.md)。
- 前置:同一独立、空闲示例应用下的两个命名空间,凭据显式具备应用资源管理权限;不需要 Worker。 - 前置:同一独立、空闲示例应用下的两个命名空间,凭据显式具备应用资源管理权限;不需要 Worker。
- 步骤:应用上限设为 1 → first 受理 → second 全局满额 → 取消 first → second 以原受理键成功 → 取消收尾并按 CAS 恢复配置。 - 步骤:应用上限设为 1 → first 受理 → second 全局满额 → 取消 first → second 以原受理键成功 → 取消收尾并按 CAS 恢复配置。
- 预期:APPLICATION_FULL/429、same_identity_retry_accepted=true、三个用量归零。 - 预期:APPLICATION_FULL/429、same_identity_retry_accepted=true、三个用量归零。
@@ -134,9 +136,9 @@
## 计划场景与验收标准 ## 计划场景与验收标准
已可运行的 [优先级场景](../api/priority-and-fairness.md#4-sdk-完整场景) 提供 [完整源码](../../sdk/go/examples/priority/main.go):按 0、9、4 受理后,以单槽 Worker 按 9、4、0 完成近同时到期的任务。前置为当前迁移/服务与队列、任务及 Worker 权限;预期 completed=3、attempts_per_task=1、worker_drained=true。无外部业务副作用,历史保留,失败非零退出,任务自带总时限;长等待补偿和其他应用隔离由真实数据库回归验证。 已可运行的 [优先级场景](../api/priority-and-fairness.md#4-sdk-完整场景) 提供 [完整源码](../../examples/priority/main.go):按 0、9、4 受理后,以单槽 Worker 按 9、4、0 完成近同时到期的任务。前置为当前迁移/服务与队列、任务及 Worker 权限;预期 completed=3、attempts_per_task=1、worker_drained=true。无外部业务副作用,历史保留,失败非零退出,任务自带总时限;长等待补偿和其他应用隔离由真实数据库回归验证。
已可运行的 [跨队列资源互斥场景](../api/keyed-concurrency.md#5-完整可运行场景) 提供 [完整源码](../../sdk/go/examples/keyed-concurrency/main.go):两个队列的自动 Worker 操作同一资源,核对递增序号,并模拟资源端拒绝旧写入。输入使用显式 concurrency_key;预期 completed=2、resource_writes=2、stale_write_rejected=true。示例仅使用受控内存资源,无外部副作用;正常排空、保留历史,任务自带总时限。内存 mutex 不是生产分布式存储,生产必须在资源端原子持久化序号、操作身份和实际更新。 已可运行的 [跨队列资源互斥场景](../api/keyed-concurrency.md#5-完整可运行场景) 提供 [完整源码](../../examples/keyed-concurrency/main.go):两个队列的自动 Worker 操作同一资源,核对递增序号,并模拟资源端拒绝旧写入。输入使用显式 concurrency_key;预期 completed=2、resource_writes=2、stale_write_rejected=true。示例仅使用受控内存资源,无外部副作用;正常排空、保留历史,任务自带总时限。内存 mutex 不是生产分布式存储,生产必须在资源端原子持久化序号、操作身份和实际更新。
| 场景 | 输入与步骤 | 预期结果 | 必测异常 | 状态 | | 场景 | 输入与步骤 | 预期结果 | 必测异常 | 状态 |
| --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- |
@@ -151,7 +153,7 @@
## 已可运行:订阅管理与幂等回执 ## 已可运行:订阅管理与幂等回执
- 源码:[订阅管理示例](../../sdk/go/examples/subscriptions/main.go),[启动、输入输出和异常说明](subscriptions.md)。 - 源码:[订阅管理示例](../../examples/subscriptions/main.go),[启动、输入输出和异常说明](subscriptions.md)。
- 前置:当前迁移及服务,具备 events:manage/read/consume 的专用开发凭据;初始化显式 --event-access。 - 前置:当前迁移及服务,具备 events:manage/read/consume 的专用开发凭据;初始化显式 --event-access。
- 步骤:创建 → 同键核对 → 暂停 → 恢复 → 查询与分页 → 最终暂停。 - 步骤:创建 → 同键核对 → 暂停 → 恢复 → 查询与分页 → 最终暂停。
- 预期:duplicate=true、resumed_revision=3、final_enabled=false、revision=4、pending=0。 - 预期:duplicate=true、resumed_revision=3、final_enabled=false、revision=4、pending=0。
@@ -160,7 +162,7 @@
## 已可运行:结果消费协议与跨连接确认 ## 已可运行:结果消费协议与跨连接确认
- 源码:[事件协议示例](../../sdk/go/examples/event-protocol/main.go),[启动与输出说明](event-protocol.md)。 - 源码:[事件协议示例](../../examples/event-protocol/main.go),[启动与输出说明](event-protocol.md)。
- 操作:创建订阅 → 提交并取消任务 → 接收冻结结果 → ACK → 重连重报原证明 → 核对原确认时间 → 暂停订阅。 - 操作:创建订阅 → 提交并取消任务 → 接收冻结结果 → ACK → 重连重报原证明 → 核对原确认时间 → 暂停订阅。
- 输出:ack_replayed=true、same_receipt=true、pending=0、subscription_enabled=false。 - 输出:ack_replayed=true、same_receipt=true、pending=0、subscription_enabled=false。
- 范围:本例只做读取验证,不写业务数据;[自动消费器](../sdk/event-consumer.md) 的生产接入须提供事务Inbox,不能把示例当作业务恰好一次保证。 - 范围:本例只做读取验证,不写业务数据;[自动消费器](../sdk/event-consumer.md) 的生产接入须提供事务Inbox,不能把示例当作业务恰好一次保证。
@@ -175,7 +177,7 @@
## 已可运行:批量受理与部分补交 ## 已可运行:批量受理与部分补交
- 源码:[batch](../../sdk/go/examples/batch/main.go),[完整启动命令和输出](batch.md)。 - 源码:[batch](../../examples/batch/main.go),[完整启动命令和输出](batch.md)。
- 步骤:独立暂停队列 → 三项批量提交、两项成功一项满额 → 整批核对原回执 → 取消释放额度 → 仅原身份补交第三项 → 取消收尾。 - 步骤:独立暂停队列 → 三项批量提交、两项成功一项满额 → 整批核对原回执 → 取消释放额度 → 仅原身份补交第三项 → 取消收尾。
- 预期:accepted=2、replayed=2、retried_items=1、unfinished=0。 - 预期:accepted=2、replayed=2、retried_items=1、unfinished=0。
- 异常:逐项区分REJECTED/UNKNOWN/NOT_ATTEMPTED;真实HTTP响应丢失后恢复无重复,保留当前权限和额度控制。 - 异常:逐项区分REJECTED/UNKNOWN/NOT_ATTEMPTED;真实HTTP响应丢失后恢复无重复,保留当前权限和额度控制。
@@ -183,7 +185,7 @@
## 已可运行:独立任务人工核查与关联重试 ## 已可运行:独立任务人工核查与关联重试
- 源码:[recovery](../../sdk/go/examples/recovery/main.go),[完整运行与失败说明](recovery.md)。 - 源码:[recovery](../../examples/recovery/main.go),[完整运行与失败说明](recovery.md)。
- 步骤:模拟UNKNOWN → 人工声明历史执行结束 → 核查FAILED → 原键核对 → 创建retry_of关联新任务 → 执行成功 → 查询原任务及操作审计。 - 步骤:模拟UNKNOWN → 人工声明历史执行结束 → 核查FAILED → 原键核对 → 创建retry_of关联新任务 → 执行成功 → 查询原任务及操作审计。
- 预期:原任务FAILED、新任务SUCCEEDED,原尝试和审计保留;管理凭据显式--recovery-access。 - 预期:原任务FAILED、新任务SUCCEEDED,原尝试和审计保留;管理凭据显式--recovery-access。
- 异常:真实HTTP在核查/重试提交后丢响应,原身份恢复同一审计和新任务;迟到成功只进入证据。 - 异常:真实HTTP在核查/重试提交后丢响应,原身份恢复同一审计和新任务;迟到成功只进入证据。
@@ -191,7 +193,7 @@
## 已可运行:业务键和创建时间查询 ## 已可运行:业务键和创建时间查询
- 源码:[task-query](../../sdk/go/examples/task-query/main.go),[完整启动与异常说明](task-query.md)。 - 源码:[task-query](../../examples/task-query/main.go),[完整启动与异常说明](task-query.md)。
- 步骤:提交三个模拟任务 → 精确业务键及时间范围过滤 → 每页一条遍历 → 验证上界排除 → 取消收尾。 - 步骤:提交三个模拟任务 → 精确业务键及时间范围过滤 → 每页一条遍历 → 验证上界排除 → 取消收尾。
- 预期:matched=2、pages=2、before_excluded=true、cancelled=3。 - 预期:matched=2、pages=2、before_excluded=true、cancelled=3。
- 范围:普通提交/读取/取消权限;不调用外部系统、不启动Worker,所有历史保留,状态分页不是数据库快照。 - 范围:普通提交/读取/取消权限;不调用外部系统、不启动Worker,所有历史保留,状态分页不是数据库快照。

View File

@@ -1,6 +1,6 @@
# 批量文件作业受理与部分补交 # 批量文件作业受理与部分补交
[完整源码](../../sdk/go/examples/batch/main.go) 使用独立Go SDK,不导入服务端模型或数据库驱动。它演示受理与取消,不启动Worker或转换真实文件。 [完整源码](../../examples/batch/main.go) 使用独立Go SDK,不导入服务端模型或数据库驱动。它演示受理与取消,不启动Worker或转换真实文件。
## 前置与运行 ## 前置与运行
@@ -21,10 +21,10 @@ go run ./cmd/orbit
另开终端: 另开终端:
```sh ```sh
cd sdk/go cd examples
ORBIT_URL=http://127.0.0.1:8080 \ ORBIT_URL=http://127.0.0.1:8080 \
ORBIT_CREDENTIALS_FILE=../../.local/batch.credentials.json \ ORBIT_CREDENTIALS_FILE=../.local/batch.credentials.json \
go run ./examples/batch go run ./batch
``` ```
也接受ORBIT_TOKEN,环境值优先。示例自行创建并暂停一个独立队列,未终结上限为2,不改变已有队列或应用配置。前置应用剩余额度至少2。 也接受ORBIT_TOKEN,环境值优先。示例自行创建并暂停一个独立队列,未终结上限为2,不改变已有队列或应用配置。前置应用剩余额度至少2。

View File

@@ -1,16 +1,16 @@
# 相对延迟与原请求恢复 # 相对延迟与原请求恢复
源码:[delayed-task/main.go](../../sdk/go/examples/delayed-task/main.go)。示例提交等待1500毫秒的对象任务,启动自动Worker,核对实际执行历史,再在任务完成后重报原请求。处理器原样返回示例JSON,无外部副作用。 源码:[delayed-task/main.go](../../examples/delayed-task/main.go)。示例提交等待1500毫秒的对象任务,启动自动Worker,核对实际执行历史,再在任务完成后重报原请求。处理器原样返回示例JSON,无外部副作用。
## 准备与运行 ## 准备与运行
先完成[迁移和Worker凭据初始化](../sdk/worker.md#1-可运行的文本规范化示例),启动当前Orbit。凭据需要任务提交、读取及Worker连接/消费权限,队列须有可用额度。仓库根目录执行: 先完成[迁移和Worker凭据初始化](../sdk/worker.md#1-可运行的文本规范化示例),启动当前Orbit。凭据需要任务提交、读取及Worker连接/消费权限,队列须有可用额度。仓库根目录执行:
```sh ```sh
cd sdk/go cd examples
ORBIT_URL=http://127.0.0.1:8080 \ ORBIT_URL=http://127.0.0.1:8080 \
ORBIT_CREDENTIALS_FILE=../../.local/worker.credentials.json \ ORBIT_CREDENTIALS_FILE=../.local/worker.credentials.json \
go run ./examples/delayed-task go run ./delayed-task
``` ```
也可用ORBIT_TOKEN和ORBIT_QUEUE_ID覆盖凭据文件中的对应值。示例总上下文20秒、任务总时限15秒、单次执行5秒、最多1次尝试;每次运行使用独立操作及处理器身份,不会消费其他处理器的任务。 也可用ORBIT_TOKEN和ORBIT_QUEUE_ID覆盖凭据文件中的对应值。示例总上下文20秒、任务总时限15秒、单次执行5秒、最多1次尝试;每次运行使用独立操作及处理器身份,不会消费其他处理器的任务。

View File

@@ -1,6 +1,6 @@
# 结果消费协议示例 # 结果消费协议示例
[完整代码](../../sdk/go/examples/event-protocol/main.go) 使用正式 Go SDK 创建取消结果订阅,提交并取消一个待执行任务,接收并验证冻结结果,然后 ACK;关闭连接后在新连接中重报原证明,验证原确认时间和去重回执,最后暂停本次订阅。 [完整代码](../../examples/event-protocol/main.go) 使用正式 Go SDK 创建取消结果订阅,提交并取消一个待执行任务,接收并验证冻结结果,然后 ACK;关闭连接后在新连接中重报原证明,验证原确认时间和去重回执,最后暂停本次订阅。
本例只读取并验证结果,没有业务数据库写入。生产业务应使用 [自动消费器及事务去重约定](../sdk/event-consumer.md)。持久化接入见 [独立 MySQL Inbox 示例](result-inbox.md)。 本例只读取并验证结果,没有业务数据库写入。生产业务应使用 [自动消费器及事务去重约定](../sdk/event-consumer.md)。持久化接入见 [独立 MySQL Inbox 示例](result-inbox.md)。
@@ -8,12 +8,13 @@
先按 [订阅管理示例](subscriptions.md) 建立隔离示例队列和带 --event-access 的凭据,启动 Orbit。凭据需要 tasks:submit、tasks:cancel、events:manage/read/consume 及该队列范围;订阅绑定创建凭据,不能临时换凭据消费。 先按 [订阅管理示例](subscriptions.md) 建立隔离示例队列和带 --event-access 的凭据,启动 Orbit。凭据需要 tasks:submit、tasks:cancel、events:manage/read/consume 及该队列范围;订阅绑定创建凭据,不能临时换凭据消费。
从 sdk/go 目录运行: 从仓库根目录进入 examples 后运行:
```sh ```sh
cd examples
ORBIT_URL=http://127.0.0.1:8080 \ ORBIT_URL=http://127.0.0.1:8080 \
ORBIT_CREDENTIALS_FILE=../../.local/event.credentials.json \ ORBIT_CREDENTIALS_FILE=../.local/event.credentials.json \
go run ./examples/event-protocol go run ./event-protocol
``` ```
也可以传 ORBIT_TOKEN 与 ORBIT_QUEUE_ID,环境变量覆盖凭据文件对应值。每次运行新建随机订阅及任务身份,全部流程最多 15 秒。本例是短流程,两个连接均短于一次心跳周期;长期运行必须用自动消费器或主动 Ping。 也可以传 ORBIT_TOKEN 与 ORBIT_QUEUE_ID,环境变量覆盖凭据文件对应值。每次运行新建随机订阅及任务身份,全部流程最多 15 秒。本例是短流程,两个连接均短于一次心跳周期;长期运行必须用自动消费器或主动 Ping。

View File

@@ -7,10 +7,10 @@
需要当前迁移、已启动 Orbit 服务,以及具备任务提交/读取和 Worker 消费权限的专用凭据。凭据文件应只保存在本地受保护目录: 需要当前迁移、已启动 Orbit 服务,以及具备任务提交/读取和 Worker 消费权限的专用凭据。凭据文件应只保存在本地受保护目录:
```sh ```sh
cd sdk/go cd examples
ORBIT_URL=http://127.0.0.1:8080 \ ORBIT_URL=http://127.0.0.1:8080 \
ORBIT_CREDENTIALS_FILE=../../.local/worker.credentials.json \ ORBIT_CREDENTIALS_FILE=../.local/worker.credentials.json \
go run ./examples/file-conversion go run ./file-conversion
``` ```
## 调用链与预期 ## 调用链与预期
@@ -50,8 +50,8 @@ input=records.csv output=records.json rows=2 state=SUCCEEDED worker_drained=true
单元转换校验: 单元转换校验:
```sh ```sh
cd sdk/go cd examples
GOWORK=off go test ./examples/file-conversion GOWORK=off go test ./file-conversion
``` ```
`make integration` 会在一次性 MySQL 和真实 Orbit HTTP 服务上运行该示例,确认提交、Worker 执行、结果查询和排空均通过。该场景不证明外部对象存储的持久性,也不替代生产容量、故障切换或 RPO/RTO 验收。 `make integration` 会在一次性 MySQL 和真实 Orbit HTTP 服务上运行该示例,确认提交、Worker 执行、结果查询和排空均通过。该场景不证明外部对象存储的持久性,也不替代生产容量、故障切换或 RPO/RTO 验收。

View File

@@ -1,6 +1,6 @@
# 未知结果的核查与人工重试示例 # 未知结果的核查与人工重试示例
完整源码:[SDK recovery/main.go](../../sdk/go/examples/recovery/main.go)。只处理本地模拟对象,不调用任何真实外部业务系统。接口细节见[人工恢复手册](../api/task-recovery.md)。 完整源码:[SDK recovery/main.go](../../examples/recovery/main.go)。只处理本地模拟对象,不调用任何真实外部业务系统。接口细节见[人工恢复手册](../api/task-recovery.md)。
## 准备与运行 ## 准备与运行
@@ -20,10 +20,10 @@ go run ./cmd/orbit
另开终端,从仓库根目录执行: 另开终端,从仓库根目录执行:
```sh ```sh
cd sdk/go cd examples
ORBIT_URL=http://127.0.0.1:8080 \ ORBIT_URL=http://127.0.0.1:8080 \
ORBIT_CREDENTIALS_FILE=../../.local/recovery.credentials.json \ ORBIT_CREDENTIALS_FILE=../.local/recovery.credentials.json \
go run ./examples/recovery go run ./recovery
``` ```
演示凭据为了完整运行同时包含Worker与人工管理权限;生产将它们分开。凭据文件0600、token不输出;也接受ORBIT_TOKEN/ORBIT_QUEUE_ID,环境值优先。 演示凭据为了完整运行同时包含Worker与人工管理权限;生产将它们分开。凭据文件0600、token不输出;也接受ORBIT_TOKEN/ORBIT_QUEUE_ID,环境值优先。

View File

@@ -1,6 +1,6 @@
# 订阅管理与幂等回执示例 # 订阅管理与幂等回执示例
状态:已提供 [完整可运行源码](../../sdk/go/examples/subscriptions/main.go)。演示 HTTP 管理 SDK;完整结果消费、重连及持久化 Inbox 示例继续开发。协议与字段见 [订阅接口](../api/subscriptions.md)。 状态:已提供 [完整可运行源码](../../examples/subscriptions/main.go)。演示 HTTP 管理 SDK;完整结果消费、重连及持久化 Inbox 示例继续开发。协议与字段见 [订阅接口](../api/subscriptions.md)。
## 前置和运行 ## 前置和运行
@@ -19,10 +19,10 @@ go run ./cmd/orbit
另一个终端从仓库根目录执行: 另一个终端从仓库根目录执行:
```sh ```sh
cd sdk/go cd examples
ORBIT_URL=http://127.0.0.1:8080 \ ORBIT_URL=http://127.0.0.1:8080 \
ORBIT_CREDENTIALS_FILE=../../.local/subscriptions.credentials.json \ ORBIT_CREDENTIALS_FILE=../.local/subscriptions.credentials.json \
go run ./examples/subscriptions go run ./subscriptions
``` ```
也可设置 ORBIT_TOKEN 和 ORBIT_QUEUE_ID,环境值优先于凭据文件。生产接入使用 HTTPS;不要提交凭据文件或在命令行打印秘密。 也可设置 ORBIT_TOKEN 和 ORBIT_QUEUE_ID,环境值优先于凭据文件。生产接入使用 HTTPS;不要提交凭据文件或在命令行打印秘密。

View File

@@ -1,16 +1,16 @@
# 业务键与时间范围查询示例 # 业务键与时间范围查询示例
源码:[task-query/main.go](../../sdk/go/examples/task-query/main.go)。本例提交三个模拟对象任务,不启动Worker,演示精确业务键、创建时间区间和任务摘要分页。 源码:[task-query/main.go](../../examples/task-query/main.go)。本例提交三个模拟对象任务,不启动Worker,演示精确业务键、创建时间区间和任务摘要分页。
## 准备与运行 ## 准备与运行
按[SDK初始化步骤](../sdk/README.md)迁移数据库、初始化专用开发队列及普通提交/读取/取消凭据,启动当前Orbit服务。从仓库根目录执行: 按[SDK初始化步骤](../sdk/README.md)迁移数据库、初始化专用开发队列及普通提交/读取/取消凭据,启动当前Orbit服务。从仓库根目录执行:
```sh ```sh
cd sdk/go cd examples
ORBIT_URL=http://127.0.0.1:8080 \ ORBIT_URL=http://127.0.0.1:8080 \
ORBIT_CREDENTIALS_FILE=../../.local/development.credentials.json \ ORBIT_CREDENTIALS_FILE=../.local/development.credentials.json \
go run ./examples/task-query go run ./task-query
``` ```
也可使用ORBIT_TOKEN与ORBIT_QUEUE_ID,环境值优先。无需额外管理权限,凭据秘密不输出。队列应有至少三个未终结任务空位;每次运行的处理器与业务键带独立标识,避免已有任务干扰。 也可使用ORBIT_TOKEN与ORBIT_QUEUE_ID,环境值优先。无需额外管理权限,凭据秘密不输出。队列应有至少三个未终结任务空位;每次运行的处理器与业务键带独立标识,避免已有任务干扰。

View File

@@ -2,7 +2,7 @@
本例运行真实HTTP发布与读取,验证六种节点的格式以及不可变版本。当前不创建流程实例、不执行外部业务。实际运行另见[并行作业与回执示例](workflow.md)。 本例运行真实HTTP发布与读取,验证六种节点的格式以及不可变版本。当前不创建流程实例、不执行外部业务。实际运行另见[并行作业与回执示例](workflow.md)。
源码:[workflow-definition/main.go](../../sdk/go/examples/workflow-definition/main.go)。接口:[定义发布](../api/workflow-definitions.md);字段规范:[结构版本1](../api/workflow-definition-format.md)。 源码:[workflow-definition/main.go](../../examples/workflow-definition/main.go)。接口:[定义发布](../api/workflow-definitions.md);字段规范:[结构版本1](../api/workflow-definition-format.md)。
## 1. 准备与运行 ## 1. 准备与运行
@@ -15,11 +15,11 @@ bin/orbit-admin bootstrap --application definition-demo --namespace default --en
首次创建文件后保留,不要覆盖或打印凭据内容。该标志只增加定义读取和发布动作;生产凭据应限制到需要的命名空间及队列。 首次创建文件后保留,不要覆盖或打印凭据内容。该标志只增加定义读取和发布动作;生产凭据应限制到需要的命名空间及队列。
```sh ```sh
cd sdk/go cd examples
ORBIT_URL=http://127.0.0.1:8080 \ ORBIT_URL=http://127.0.0.1:8080 \
ORBIT_CREDENTIALS_FILE=/tmp/orbit-definition.credentials.json \ ORBIT_CREDENTIALS_FILE=/tmp/orbit-definition.credentials.json \
ORBIT_OPERATION_ID=object-definition-demo-001 \ ORBIT_OPERATION_ID=object-definition-demo-001 \
go run ./examples/workflow-definition go run ./workflow-definition
``` ```
开发回环地址可用HTTP,生产使用HTTPS。可改用`ORBIT_TOKEN`及`ORBIT_QUEUE_ID`,不把Token写入URL或提交版本库。不传`ORBIT_OPERATION_ID`时随机生成并先输出;发生未知结果时保存此操作ID,保持相同队列及源码再次运行。已成功的相同操作ID也可以重复执行,旧版本与revision不会增加。 开发回环地址可用HTTP,生产使用HTTPS。可改用`ORBIT_TOKEN`及`ORBIT_QUEUE_ID`,不把Token写入URL或提交版本库。不传`ORBIT_OPERATION_ID`时随机生成并先输出;发生未知结果时保存此操作ID,保持相同队列及源码再次运行。已成功的相同操作ID也可以重复执行,旧版本与revision不会增加。

View File

@@ -1,6 +1,6 @@
# 有界轮询:请求重试与业务轮次分别计数 # 有界轮询:请求重试与业务轮次分别计数
[完整源码](../../sdk/go/examples/workflow-poll/main.go)通过公共SDK发布POLL定义,启动真实Worker,并请求一个本机HTTP渠道夹具。流程先由TASK向本机渠道提交一次作业,受理回执提供固定operation_id,随后POLL只查询这个作业;平台没有集成任何具体业务渠道。 [完整源码](../../examples/workflow-poll/main.go)通过公共SDK发布POLL定义,启动真实Worker,并请求一个本机HTTP渠道夹具。流程先由TASK向本机渠道提交一次作业,受理回执提供固定operation_id,随后POLL只查询这个作业;平台没有集成任何具体业务渠道。
同一命令依次运行两个流程: 同一命令依次运行两个流程:
@@ -27,10 +27,10 @@ go run ./cmd/orbit
bootstrap只执行一次,凭据文件存在时不会覆盖。另开终端,从仓库根目录运行: bootstrap只执行一次,凭据文件存在时不会覆盖。另开终端,从仓库根目录运行:
```sh ```sh
cd sdk/go cd examples
ORBIT_URL=http://127.0.0.1:8080 \ ORBIT_URL=http://127.0.0.1:8080 \
ORBIT_CREDENTIALS_FILE=../../.local/poll.credentials.json \ ORBIT_CREDENTIALS_FILE=../.local/poll.credentials.json \
go run ./examples/workflow-poll go run ./workflow-poll
``` ```
程序自行创建并关闭本机HTTP夹具,不需要启动第三方系统,不向公网提交操作。正式接入使用HTTPS/WSS和分角色凭据,将只读查询处理器替换为自己的渠道调用。 程序自行创建并关闭本机HTTP夹具,不需要启动第三方系统,不向公网提交操作。正式接入使用HTTPS/WSS和分角色凭据,将只读查询处理器替换为自己的渠道调用。

View File

@@ -2,7 +2,7 @@
场景:一个对象关联多次处理流程,管理端需要按固定定义版本、精确业务关联及时间范围查询等待中的实例,再进入详情处理。示例同时证明业务键末尾有无空格属于不同关联。 场景:一个对象关联多次处理流程,管理端需要按固定定义版本、精确业务关联及时间范围查询等待中的实例,再进入详情处理。示例同时证明业务键末尾有无空格属于不同关联。
源码:[workflow-query/main.go](../../sdk/go/examples/workflow-query/main.go)。服务端入口:[筛选接口](../api/workflow-queries.md)。示例发布一个SIGNAL等待流程,创建三个实例,其中两个使用相同业务键、第三个去掉尾部空格;每页1项读取匹配的两个实例,最后将三个实例取消并等待CANCELLED。 源码:[workflow-query/main.go](../../examples/workflow-query/main.go)。服务端入口:[筛选接口](../api/workflow-queries.md)。示例发布一个SIGNAL等待流程,创建三个实例,其中两个使用相同业务键、第三个去掉尾部空格;每页1项读取匹配的两个实例,最后将三个实例取消并等待CANCELLED。
## 启动 ## 启动
@@ -22,10 +22,10 @@ go run ./cmd/orbit
另开终端: 另开终端:
```sh ```sh
cd sdk/go cd examples
ORBIT_URL=http://127.0.0.1:8080 \ ORBIT_URL=http://127.0.0.1:8080 \
ORBIT_CREDENTIALS_FILE=../../.local/workflow-query.credentials.json \ ORBIT_CREDENTIALS_FILE=../.local/workflow-query.credentials.json \
go run ./examples/workflow-query go run ./workflow-query
``` ```
查询本身只要求workflows:read。此完整示例额外需要研发创建/发布、启动与控制权限,由上述bootstrap选项授予。SIGNAL等待不用Worker,也不模拟外部业务成功;正常结束通过显式取消结清。 查询本身只要求workflows:read。此完整示例额外需要研发创建/发布、启动与控制权限,由上述bootstrap选项授予。SIGNAL等待不用Worker,也不模拟外部业务成功;正常结束通过显式取消结清。

View File

@@ -1,6 +1,6 @@
# 提交后回执丢失:核查、暂停与有证据恢复 # 提交后回执丢失:核查、暂停与有证据恢复
[完整源码](../../sdk/go/examples/workflow-recovery/main.go)使用真实Orbit、自动Worker和本机HTTP渠道夹具。夹具先保存外部提交结果,再直接关闭连接,确保Worker实际遇到传输错误。流程进入NEEDS_REVIEW后,程序在受控夹具中模拟一个已经核实事实的管理员,逐项提交恢复决定。 [完整源码](../../examples/workflow-recovery/main.go)使用真实Orbit、自动Worker和本机HTTP渠道夹具。夹具先保存外部提交结果,再直接关闭连接,确保Worker实际遇到传输错误。流程进入NEEDS_REVIEW后,程序在受控夹具中模拟一个已经核实事实的管理员,逐项提交恢复决定。
这是一份可运行的SDK接入与故障示例。夹具数据仅在本次进程内保存;真实系统需要持久证据和真实授权,不能把下面的演示核查逻辑接成任意业务的自动放行。 这是一份可运行的SDK接入与故障示例。夹具数据仅在本次进程内保存;真实系统需要持久证据和真实授权,不能把下面的演示核查逻辑接成任意业务的自动放行。
@@ -23,10 +23,10 @@ go run ./cmd/orbit
初始化一次;原凭据文件不会被覆盖。另开终端,从仓库根目录运行: 初始化一次;原凭据文件不会被覆盖。另开终端,从仓库根目录运行:
```sh ```sh
cd sdk/go cd examples
ORBIT_URL=http://127.0.0.1:8080 \ ORBIT_URL=http://127.0.0.1:8080 \
ORBIT_CREDENTIALS_FILE=../../.local/workflow-recovery.credentials.json \ ORBIT_CREDENTIALS_FILE=../.local/workflow-recovery.credentials.json \
go run ./examples/workflow-recovery go run ./workflow-recovery
``` ```
开发凭据包含定义、启动、Worker、控制、恢复及审计权限,便于单命令演示。正式接入应使用HTTPS/WSS,并为业务Worker与管理员分别签发所需权限;Worker执行权不自动授予恢复权。 开发凭据包含定义、启动、Worker、控制、恢复及审计权限,便于单命令演示。正式接入应使用HTTPS/WSS,并为业务Worker与管理员分别签发所需权限;Worker执行权不自动授予恢复权。

View File

@@ -1,6 +1,6 @@
# 并行生成结果 → 等待外部回执 → 后续任务 # 并行生成结果 → 等待外部回执 → 后续任务
[完整源码](../../sdk/go/examples/workflow/main.go)通过独立Go SDK发布固定版本、启动实例,并使用真实自动Worker处理任务。流程是两个文本规范化任务并行完成并汇合,等待500毫秒,等待模拟外部确认信号,最后用左侧输出执行发布步骤。输入为 `{"text":" hello orbit "}`,输出为 `{"text":"HELLO ORBIT"}`。 [完整源码](../../examples/workflow/main.go)通过独立Go SDK发布固定版本、启动实例,并使用真实自动Worker处理任务。流程是两个文本规范化任务并行完成并汇合,等待500毫秒,等待模拟外部确认信号,最后用左侧输出执行发布步骤。输入为 `{"text":" hello orbit "}`,输出为 `{"text":"HELLO ORBIT"}`。
## 1. 启动 ## 1. 启动
@@ -21,10 +21,10 @@ go run ./cmd/orbit
初始化仅执行一次,文件存在时不会覆盖。重用该凭据运行例子无需重复bootstrap。另开终端,从仓库根目录执行: 初始化仅执行一次,文件存在时不会覆盖。重用该凭据运行例子无需重复bootstrap。另开终端,从仓库根目录执行:
```sh ```sh
cd sdk/go cd examples
ORBIT_URL=http://127.0.0.1:8080 \ ORBIT_URL=http://127.0.0.1:8080 \
ORBIT_CREDENTIALS_FILE=../../.local/workflow.credentials.json \ ORBIT_CREDENTIALS_FILE=../.local/workflow.credentials.json \
go run ./examples/workflow go run ./workflow
``` ```
生产使用HTTPS/WSS,并为定义发布者、启动者、信号发送者及Worker分别签发所需权限。本示例使用一个专用开发凭据,未申请人工恢复或控制权限。 生产使用HTTPS/WSS,并为定义发布者、启动者、信号发送者及Worker分别签发所需权限。本示例使用一个专用开发凭据,未申请人工恢复或控制权限。

View File

@@ -0,0 +1,29 @@
# 单管理员应用接入验收(2026-09-27)
本报告记录当时的立即换证语义;后续长期凭据和双 Token 过渡已在[增量报告](credential-overlap.md)单独说明。
## 交付范围
- 独立应用接入页:按应用/环境查看接入范围、队列与凭据,创建应用/命名空间/初始队列,选择业务能力,生成或轮换 Token,复制/下载 SDK 环境配置。
- 通过 `ORBIT_CONSOLE_APPLICATION_ADMIN` 显式指定唯一管理员,默认关闭;仅登录 Cookie 可访问管理端,业务 Token 不授予跨应用权限。同事务核验账号及会话,写请求额外核验同源与专用请求头。
- 新建资源、权限、审计、幂等回执同事务;轮换复用原凭据事务与 ID,任务、订阅和交付身份保留。只存秘密摘要,一次性交付明文;提交不明时保留原操作核对。
- 没有新增数据库表或外键,没有改变业务 SDK 接口,不需要升级 SDK v0.1.1。
## 已完成验证
| 验证 | 结果 |
| --- | --- |
| `make test vet build` | 七模块竞态测试、静态检查和构建通过 |
| `TestIntegrationConsoleApplications` | 真实 MySQL:SDK 身份与错误管理员拒绝、准备未生效、并发创建一次、同键改内容冲突、重名回滚、元数据脱敏、轮换原身份、旧秘密失效、重复回执、版本冲突、退出失效、审计主体及零外键通过 |
| 管理 HTTP 单元测试 | Cookie 必须、Bearer 单独拒绝、缺少防跨站头/异源/null Origin 拒绝、合法同源请求、未知字段拒绝、响应不可缓存通过 |
| 准备对象严格 JSON 往返 | CREATE 与 ROTATE 的可选 ID/空能力组原样提交通过;真实 HTTP 发现的空 ID 编码问题已修复并加入回归 |
| `scripts/test-console-applications.py` | 真实 HTTP 创建/重放/冲突,任务和订阅生成,轮换后旧 Token 401、新 Token 可读取原任务与订阅,订阅暂停收尾、退出会话失效通过 |
| `make console-e2e` | 全新 MySQL/容器初始化,应用接入新链路、登录/权限、真实 Worker/重试/定时、保留策略、周期归档及离线校验全部通过 |
| 本地 Compose | 更新现有 18080 环境,复用原管理员、初始业务凭据与数据库卷;新增独立 access-demo 测试应用,轮换只发生于该测试应用 |
| 浏览器检查 | 实际账号登录,独立页面与应用详情加载、新建表单显示、权限/队列/配置展示;当前 1280×720 视口布局正常,无浏览器错误 |
`make integration` 已完整退出 0:覆盖真实存储、HTTP/WSS、SDK、可运行示例、独立 Inbox/Outbox/HTTP 宿主、Worker 与事件进程故障以及流程多节点暂停恢复。页面布局与表单读取通过浏览器核对;实际创建与轮换的持久化链路通过真实 HTTP 验证,不混称为浏览器点击完成全部流程。文档链接检查覆盖 196 份 Markdown,全部解析通过。
## 边界
接入管理跨应用,其他业务页面仍使用账号原有默认范围。旧 Token 原文不可查看;新 Token 交付丢失时保留原应用并重新轮换。列表每页 50 个命名空间,单个详情队列和凭据各最多 100 项并显式标记截断。当前未增加删除应用、修改权限、凭据转移、复杂角色或多应用任务总览。

View File

@@ -0,0 +1,88 @@
# 管理端简化与操作体验验收
日期:2026-09-29。仅调整内置控制台、查询状态与使用说明;API、SDK、MySQL 模型和权限不变。
## 交付内容
- 统一浅色工作台、分组导航、紧凑总览、中文状态、表格、详情和登录页。
- 总览按各类最近 20 条记录展示快照,明确统计范围,取消与失败分别显示;需要关注的项目可进入对应列表。
- 任务/流程通过已有服务端 API 组合状态、精确业务键、创建时间查询;任务/计划/流程/订阅使用服务端游标翻页,支持 20/50/100 条与直接 ID 定位。
- 刷新保留条件和当前游标;新查询失效旧响应,详情关闭或换资源后忽略旧响应。详情焦点留在抽屉,关闭回到入口,完整 ID 可复制。
- 应用接入支持本页搜索;凭据配置为主要操作,技术标识、权限和低频管理操作折叠。管理员仍可查看和复制含 Token 的完整接入配置。
- 仅刷新当前页;自动刷新可暂停,打开详情、操作弹窗或编辑输入时不自动打断。
## 自动回归
- `make test vet build`:根模块、SDK、示例与适配包竞态测试、静态检查和构建通过。
- `make console-check`:JS 语法检查及 4 项查询状态回归通过。覆盖特殊字符/尾空格、游标条件不丢失、迟到响应隔离、失败保留查询、时间边界及流程命名空间范围。
- `make console-e2e`:隔离 MySQL 容器通过登录/未登录保护、CSRF、跨应用隔离、Token 查看/导入、换证过渡、订阅/队列退役、真实 WS Worker、任务重试、定时触发、归档及退出登录回归。
- HTML ID 唯一性检查通过。运行服务无需 Node.js 或新前端依赖。
## 浏览器与数据
本地同源预览使用当前持久 MySQL 数据;独立队列 `console-ui-297f4c61f275` 用于 25 条测试任务的分页验证。测试任务使用专用处理器且未启动 Worker,全部取消,无外部副作用。保留记录供复查。
已核对:
- 20 条首屏 → 5 条第二页 → 刷新仍在第二页 → 上一页;50 条页大小返回 25 条。
- 精确查询 `筛选 +%_ `(尾部两个空格)仅返回对应的一条记录;结束时间早于开始时间被阻止。
- 原联调队列 13 条记录按已取消状态查到 2 条;ID 定位、详情审计、复制完整 ID 通过。
- 定时计划当前规则/触发历史、流程步骤/事件/输出、订阅交付、保留策略只读预览及归档空态均可读取。
- 应用搜索、明确队列选择、查看/复制完整配置通过;检查仅记录存在性,不把 Token、Cookie 或密码写入报告/截图。
- 1440×1000 桌面与 390×844 窄屏检查:页面不横向溢出,窄屏表格在自身容器内滚动,登录页面适配。
## 口径与边界
首页不是全局累计统计;列表游标不承诺并发变更下的固定快照;详情历史仍是最近 20 条。应用搜索只搜索本页。完整浏览器重载会重置列表条件与页码,应用/队列范围从 URL 恢复。
本批不创建新的 SDK 标签,不变更或轮换现有业务凭据,不改变单管理员模式,不将 UI 回归当作生产容量验收。代码交付在 `main`,本地运行版本以 `/version` 中的构建修订为准。
## 本地部署复核
`scripts/orbit-local.py up` 已完成持久 Compose 环境更新。`http://127.0.0.1:18080/version` 返回构建修订 `92a40f4a37ece6c30396fcdf95fe2e73076dc5b5`,`/health/ready` 返回 `ready`。原管理员登录成功,从未登录任务链接进入时,登录后返回原任务页;正式本地入口的任务读取、应用搜索和总览通过,浏览器无 JavaScript 错误。
SDK、数据库 Schema 34、原应用与凭据保持。部署未重新 bootstrap;前端资源编译进原 Orbit 镜像,无额外前端服务。
## 第二轮:筛选与布局细化
- 应用/队列菜单支持已加载选项搜索、环境副标题、选中标记和无匹配提示;状态、页大小沿用同一菜单。原 select 继续承担表单值和 change 事件,无新依赖。
- 默认页大小从 20 调整为 10,另提供 20/50/100;首页最近 20 条快照与详情历史口径保持。
- 创建时间按需整行展开;长处理器名称省略显示并可悬停查看全文;主工作区限制大屏宽度,登录品牌内容在左半屏居中。
- 浏览器实测 25 条记录按 10/10/5 三页读取;切换 20 条回到第一页,查询保留特殊字符与尾部空格。
- 验证鼠标搜索并切换应用/队列、方向键/Home/End/Enter/Escape/Tab、无匹配提示、重置恢复原始状态、错误时间范围提示、未保存策略阻止范围切换且菜单恢复原值。
- 八个页面可正常打开;1440×1000、2048×1195 和 390×844 检查大屏及移动布局;手机菜单保持在视口内。
- 本轮基础 test/vet/build、控制台端到端和 console-check/docs-check 通过。部署复核另附下方。
第二轮已部署至持久 Compose 环境:`/version` 修订为 `df76dcb9c0b69b3c947d112de619737145c44015`,就绪检查 HTTP 200。实际 18080 入口应用菜单、10 条列表、退出和原管理员登录通过;原应用身份与数据库保留。本次不涉及 SDK 发版。
## 第三轮:滚动稳定性
原布局让整个 document 滚动,页头会被带离视口;应用详情每次轮询都重建 DOM。改为固定视口的工作台、独立内容滚动、固定页头和桌面应用目录;后台请求在返回时再次检查滚动/编辑状态,相同应用快照保留原有 DOM。切换视图重置内容滚动区域,菜单仍按当前控件坐标定位。
浏览器验证:1440×900 与 390×844 下,document 不滚动,页头和导航坐标固定;鼠标点击页头刷新前后内容 scrollTop 均为 293、scrollHeight 均为 1193;展开状态不因相同快照刷新被折叠;手机切页归零、详情打开/关闭和菜单定位通过,无横向页面溢出或 JS 错误。基础 test/vet/build、console-check/docs-check 通过。
第三轮当时的登录保护核对:`ConsoleAuthStore.Login` 与 HTTP 登录路由没有失败计数、临时锁定和登录限流;当时仅记录缺口。下方 2026-09-30 专项已补齐这些能力。
第三轮持久部署已核验:`/version` 修订 `23db3d8fe0de352be9e756f932b12559ea746ff3`,`/health/ready` 为 200 ready。实际 18080 应用页内容 scrollTop=293 时,document scrollY=0、导航和页头 top=0。服务原账号、SDK、Token 和数据库保持不变。
## 2026-09-30:边界回弹与登录保护
上一轮键盘翻页和静态位置检查没有覆盖触控板滚到边界的回弹。原 `overscroll-behavior: contain` 只阻止滚动传递,仍允许元素回弹([MDN 属性说明](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/overscroll-behavior#values))。本轮在控制台根节点、侧栏、内容、应用列表及弹层的实际滚动容器设置 `none`,并固定根工作区;保留内容正常滚动和短屏菜单可达性。
浏览器预览验证:
- 1440×900,用滚动操作连续冲顶部、底部并反向:根 scrollY=0,侧栏 y=0、品牌 y=28、页头 y=0;内容 scrollTop 在 0–293 内移动。
- 1100×600,菜单在 0–198 内滚动,内容在 0–593 内独立滚动,另一侧不被拖动,页头 y=0。
- 390×844,顶部导航固定,内容滚动至 1112;根 scrollY=0、文档宽度 390,无根横向溢出。工具滚动不等同于所有设备的物理触控板惯性手势,以上为实际验证范围。
登录保护实现、配置和 API 见[控制台登录保护](../console-login-security.md)。已有真实 MySQL 回归覆盖失败/成功计数重置、两个存储实例与重建实例共用锁定、锁定不续期与自然到期、并发 6 次失败精确计数、账号/IP 配额、未知账号、失败窗口、审计提交失败回滚会话、管理员权限/分页、日志保留和零外键。独立 Docker 双服务实测还覆盖轮流失败、重启服务仍拒绝、已登录会话仍有效、伪造代理头无效、自然到期后登录成功。
端到端首轮旧管理查询曾超时;复跑该链路通过,未放宽断言。双节点测试首次重启后因 Docker 重新分配随机发布端口无法就绪,测试工具改为重读实际端口后通过,未修改锁定逻辑或删除状态。最终 `make console-e2e` 全链路通过,含任务执行、重试、定时计划、归档及退出登录。
本地持久 Compose 部署版本 `f56f233704700d43c6733b7f0fa14d67e1feddf7`,数据库 Schema 35、0 外键,readiness 为 ready。已有账号、密码、会话、凭据与业务记录未重新初始化。实际 18080 浏览器验证:独立的未知测试登录名在第 5 次错误后显示 15 分钟倒计时;真实管理员正常登录,回到原应用页,审计显示失败、锁定与成功。正式页面滚动至 293 时,根 y=0、侧栏 y=0、品牌 y=28、页头 y=0,无浏览器 JS 错误。
截图存放在本地忽略目录 `.local/console-ui-check/`:`login-locked.png`、`login-audit.png`、`scroll-boundary-fixed.png`,不含密码/Token 原文。
基础 `make test vet build console-check docs-check` 通过;真实 MySQL 存储全套通过,包含新保护专项 6 个子场景;独立 `make console-e2e` 通过。广泛 `make integration` 执行至 SDK 调度容量样本时,Docker 引擎读操作及旧服务健康请求均超时,样本未完成,因此这一次命令不记为通过。引擎自行恢复,部署完成,未重启 Docker 或其他项目。中断位置起使用相同脚本命令及参数在新的一次性数据库补跑。
尾段补跑完成:调度样本 6/6 触发并成功,流程样本 6/6 成功;其余 SDK、可运行示例、事务 Outbox/结果 Inbox、嵌入 HTTP 服务生命周期及真实进程恢复回归全部通过。覆盖租约恢复、ACK 丢响应、慢消费者、跨节点重连、优先级/并发控制、重试与截止恢复、定时计划恢复和流程暂停恢复。日志保留于 `.local/console-ui-check/security-integration-tail.log`;首段与该次补跑共同覆盖原集成脚本范围,不描述为单次全量命令通过。

View File

@@ -0,0 +1,24 @@
# 控制台应用范围回归
## 变更
任务、计划、流程、订阅和归档列表显示应用名称与环境;保留策略及详情显示归属。管理员可选择应用环境和队列,范围保存在 URL,页面切换隔离旧数据。后台按 Cookie 会话授权,普通 SDK 不接受范围覆盖。无表结构变更,无新增外键。
## 验证记录(2026-09-27)
| 检查 | 结果 |
| --- | --- |
| `make test vet build` | 通过,服务端、SDK 和各独立示例/适配模块;最后的 HTTP 范围边界测试及编译检查也通过 |
| `make integration` | 通过:真实 MySQL 全量存储回归、HTTP/WS、SDK、Inbox/Outbox/HTTP 宿主示例、进程中断及多节点流程恢复;存储回归约 307 秒,最终 SDK 进程故障组约 131 秒 |
| `TestIntegrationConsoleScope` | 原始/目标元数据、普通账号队列白名单、二进制 ID 游标、SDK/非指定管理员拒绝、目标队列隔离、仅管理不受理新工作、目标保留策略原键重放、原应用不变、人类审计、停用目标/退出后旧范围拒绝、零外键断言 |
| `make console-e2e` | 通过:隔离 MySQL 和实际 Orbit 容器;新建应用、任务/计划/流程/订阅/保留/归档范围读取,订阅管理及重放保留原 SDK 归属,跨应用单条 404、列表无泄漏,Bearer 混用/跨站写入拒绝,退出后 401;原任务执行、计划和归档端到端也通过 |
| HTTP 范围边界 | 通过 11 个 Cookie/Bearer/CSRF/读写入口场景;Worker、结果消费和资源创建不能借管理范围获得权限 |
| 静态与配置检查 | JS 语法、Python 编译、Markdown 链接、`git diff --check` 通过;单节点 + HA Compose 配置解析通过,双节点使用同一管理员环境配置 |
| 浏览器实际页面 | 任务列和订阅列表/详情显示应用标签;应用及队列切换、无数据范围、保留策略和归档范围提示、非法范围不降级、重置范围恢复均已检查 |
| 本地部署 | 本地 Compose 已部署本批代码;现有两个应用分别读取自己的范围,原 SDK Token 仍有效,无业务接入参数变更 |
应用、队列名称来自授权后的数据库元数据;队列分页首屏不使用空 ID,白名单使用 BINARY ID 参数。URL 中显式指定其他应用的队列会校验失败,不静默切换队列。打开详情、策略未保存或操作结果未确认时,页面阻止切换范围。
## 边界
当前按所选应用环境分别查看,不提供跨应用混合分页或全库统计。任务、计划、订阅按队列筛选;流程、保留与归档按命名空间展示。应用目录 50 项一页、队列 100 项一页。普通账号保留原绑定权限;只有部署指定的单管理员具有显式管理范围。此回归不替代生产部署的容量和跨故障域验收。

View File

@@ -0,0 +1,34 @@
# 长期凭据与平滑换证(2026-09-27)
新建应用与 bootstrap 默认长期 Token,可选有限有效期。已有 Token 支持 SET_EXPIRY 原地修改有效期,原秘密和接入配置保持不变;默认换证保留 7 天过渡,支持按配置调整,确认全部服务切换后可提前 FINALIZE。REVOKE 同时拒绝两代秘密。
## 实现与兼容
- 000032 在 orbit_credentials 增加 previous_secret_digest、previous_valid_until,CHECK 要求成对为空/非空。中文模型与 SQL 注释齐全,当前空库基线为 32,无外键。历史迁移不修改。
- 认证在原事务共享锁下读取两代摘要及各自截止;HTTP 和 Worker/结果消费复用原认证入口。截止使用数据库时间,不依赖内存、清理任务或节点时钟。
- 旧代实际截止不晚于其原有效期;重复轮换不会挤掉尚未切换的旧代,调整当前有效期也不会顺带延长旧代。凭据 ID、权限、任务、订阅与交付身份不变。
- 管理操作、版本、固定过渡截止、审计及幂等回执同事务。格式 v2 新增长期和过渡语义,历史 v1 仍按原固定到期/立即轮换恢复;重放历史轮换不复活已经停用的旧代。
- 管理端增加长期选项、调整有效期、平滑换证及结束过渡;CLI 增加 expiry/finalize、默认 --valid-for 0 和轮换 --grace 168h。没有修改 SDK 接口或 Token 格式。
## 验证
| 验证 | 证据 |
| --- | --- |
| 标准回归 | `make test vet build` 七模块竞态测试、静态检查和构建通过 |
| 原 Token 改长期与在途执行 | `TestIntegrationCredentialOverlap`:运行中的任务原凭据改长期后继续授权;换证期间旧 Token 续租、完成结果、释放许可;两代认证、并发原操作去重、重复轮换冲突、结束过渡、历史重报、两代撤销及审计脱敏通过 |
| 期限与旧代隔离 | `TestIntegrationCredentialOverlapDeadline`:不超过旧有效期、两代独立到期、到期无需清理即可拒绝、下一轮不复活更旧秘密通过;时间边界由隔离测试库明确设置,不把测试耗时当作长期运行证据 |
| 双节点真实 WS | `TestIntegrationCredentialOverlapWebSocket`:两个 HTTP/WS 节点共享真实 MySQL;原长连接在轮换后可发控制命令,旧 Token 可跨节点重连,新 Token 同时连接;结束过渡后旧连接命令和新握手被拒绝,新连接继续可用 |
| 提交结果未知 | `TestIntegrationCredentialCommitFaults`:COMMIT 前截断及数据库提交成功后丢确认;旧 Token 始终可用,新 Token 只在实际提交后生效,原操作核对恢复 |
| 管理 HTTP | `scripts/test-console-applications.py`:真实 Cookie 管理、CSRF、定期改长期且原 Token 200、双 Token 过渡、提前结束、旧 Token 401、新 Token 200、历史回执不能复活旧秘密、原任务/订阅读取和退出失效通过 |
| 容器端到端 | `make console-e2e` 全新 MySQL/Orbit、上述管理链路、原登录/Worker/重试/定时/归档验收通过 |
| 全量集成 | `make integration` 退出 0:真实 MySQL 全部存储用例、历史结构前向升级、HTTP/WS、独立 SDK、任务/定时/流程示例、Inbox/Outbox/HTTP 宿主、Worker/结果消费者进程故障及多节点流程恢复通过 |
| 本地升级 | 复用现有数据库卷与管理员;迁移至 32,旧 CREATE 固定对象重放命中原回执;通过有审计的 SET_EXPIRY 更新既有测试凭据,原 Token 请求 200,host.env/docker.env 字节不变,跨应用队列访问仍 404 |
| 浏览器 | 实际登录会话读取到长期有效;新建表单默认长期,平滑换证默认 7 天,调整有效期表单正确;窄窗口换证弹窗可完整操作,未通过浏览器触发实际换证 |
文档链接检查覆盖 197 份 Markdown,通过;JS 语法、Python 语法及 Git diff 检查通过。涉及 Token 的变更链路在隔离真实 HTTP/MySQL 环境验证,浏览器只验证页面和表单,不把两者混称为浏览器全链路测试。
## 使用边界
调用方在截止前完成滚动更新并正常收尾在途任务。SDK 在创建客户端时读取 Token,改 `.env` 不会热更新现有客户端;须重建客户端或逐台重启服务。单实例重启仍有短暂停顿,平台不能替业务服务保证副本容量。提前结束过渡或到期会拒绝尚未切换的旧 Token,不承诺强行停用旧身份后其连接还能继续工作。
这次数据库升级完成且所有 Orbit 节点更新后才能启用双 Token 换证;旧版本节点不认识上一代摘要。只修改有授权的本地测试凭据为长期,迁移不会自动延长其他已有凭据。完整操作顺序见[凭据手册](../api/authentication.md)和[管理接口](../api/console-applications.md)。

View File

@@ -0,0 +1,38 @@
# 管理员接入信息与 Token 保管验收
日期:2026-09-27。范围:当前 Token 的管理员查看、完整配置复制、历史凭据导入与本地部署。
## 交付行为
- 应用凭据卡片提供「查看接入信息」「复制接入配置」,弹窗可下载 `orbit.env`。
- 完整配置包含服务地址、应用 ID、命名空间 ID、授权队列 ID 和当前 Token;可指定主机、容器或域名地址。
- 关闭弹窗会清除页面中的明文,管理员可重新读取。业务列表不会自动拉取秘密。
- 新建、换证在原事务内保存 AES-256-GCM 密文;到期时间变更、结束过渡不影响回看;撤销清空密文。
- 过渡期可以查看当前新 Token。历史导入必须匹配当前摘要,旧代仍有效也不能冒充当前代次。
- 查看、导入均校验有效管理员会话、请求同源和版本;审计确认提交后才返回秘密。
## 验证
| 层次 | 验证内容 | 结果 |
| --- | --- | --- |
| 加密单测 | 随机 nonce、往返、密文篡改、跨凭据/命名空间、未知 key、保留旧 key、配置边界和格式脱敏 | 通过 |
| MySQL 专项 | 历史导入、重复导入、SDK/错误管理员拒绝、审计失败回滚与禁止交付秘密 | 通过 |
| MySQL 凭据生命周期 | 新建密文、读取/轮换并发、过渡期当前代次、拒绝旧代导入、expiry/finalize 保留、旧操作重报、旧 CLI 轮换清理、撤销清理 | 通过 |
| 历史升级 | 从历史 v9 重建并迁移到当前版本、原在途任务和额度继续结清;旧记录可空字段兼容 | 通过 |
| 标准回归 | `make test vet build`,包含根模块、SDK、示例与 Outbox 适配器 | 通过 |
| MySQL 全量存储 | `internal/storage/mysql` 的完整真实事务回归,含 `-race` | 通过 |
| HTTP/容器端到端 | `make console-e2e`:Cookie/CSRF/no-store、查看/导入、长期凭据、平滑换证及结束过渡、Worker/重试/计划/归档 | 通过 |
| 浏览器 | 完整配置字段与当前应用/授权队列一致、一键复制成功、Docker 地址切换、关闭清空、历史导入入口 | 通过 |
| 文档与格式 | 本地 Markdown 链接、JS 语法、Go 格式及 diff 检查 | 通过 |
`make integration` 已完整通过:独立 SDK、任务/计划/流程/结果订阅示例、事务 Outbox 与嵌入 HTTP 服务、跨节点重连和 Worker/Event/Workflow 全进程恢复均完成;退出码为 0。
本次回归曾发现历史升级测试还原 v9 时未移除新增密文列,以及空身份在数据库层被拒绝而非权限层拒绝;已修正并通过专项及后续全量存储回归。
## 部署与兼容边界
迁移 `000033` 增加两个有中文注释的可空字段和成对 CHECK;实际本地数据库版本 33,外键数量 0。主密钥在独立受限文件与只读卷中保存,重复部署保留,不修改应用 Token、权限、有效期或过渡截止。
历史摘要不能反推出原文。具有当前配置的应用可一次导入补齐;只有过渡期旧配置的应用仍需取得已保存的新 Token,不会自动结束过渡或重置身份。源码仓库不包含真实业务 Token、管理员密码或主密钥。
接口、密钥配置、多节点升级与备份说明见[应用接入](../api/console-applications.md)。该结果验证本次功能和本地环境,不替代生产数据库高可用及容量验收。

View File

@@ -9,7 +9,7 @@
- 受理、计划生成、领取、Start、取消、Finish、安全重试及到期恢复共同维护应用计数,跨命名空间与队列共享。空轮询与失败受理不消耗计数,重复回执不重复计费。 - 受理、计划生成、领取、Start、取消、Finish、安全重试及到期恢复共同维护应用计数,跨命名空间与队列共享。空轮询与失败受理不消耗计数,重复回执不重复计费。
- 额度行与认证身份分离,统一按应用额度 → 队列 → 任务/尝试 → 许可顺序取锁;后台扫描跳过忙碌额度,应用停用后仍可释放到期尝试。 - 额度行与认证身份分离,统一按应用额度 → 队列 → 任务/尝试 → 许可顺序取锁;后台扫描跳过忙碌额度,应用停用后仍可释放到期尝试。
- 管理 CLI 支持 `--application-id` 在已有启用应用下增加命名空间;应用管理权限必须显式 `--resource-access`,普通队列及 Worker 凭据不扩权。 - 管理 CLI 支持 `--application-id` 在已有启用应用下增加命名空间;应用管理权限必须显式 `--resource-access`,普通队列及 Worker 凭据不扩权。
- [双命名空间 SDK 示例](../../sdk/go/examples/application-resources/main.go):第一侧受理,第二侧 APPLICATION_FULL,第一侧取消释放,第二侧原身份重报成功,取消收尾并按 CAS 恢复配置。 - [双命名空间 SDK 示例](../../examples/application-resources/main.go):第一侧受理,第二侧 APPLICATION_FULL,第一侧取消释放,第二侧原身份重报成功,取消收尾并按 CAS 恢复配置。
## 2. 环境和实际回归 ## 2. 环境和实际回归

View File

@@ -7,7 +7,7 @@
- [服务契约](../../pulse/service/batch.go):最多32项,逐项独立事务与幂等,ACCEPTED/REJECTED/UNKNOWN/NOT_ATTEMPTED四类结果。未知数据库结果或凭据失效后停止余项,上下文结束保留已确认前项。 - [服务契约](../../pulse/service/batch.go):最多32项,逐项独立事务与幂等,ACCEPTED/REJECTED/UNKNOWN/NOT_ATTEMPTED四类结果。未知数据库结果或凭据失效后停止余项,上下文结束保留已确认前项。
- [HTTP入口](../../internal/transport/httpserver/tasks.go):`POST /v1/tasks:batch`,全体正文严格解析后才受理,每项正文幂等键,总请求512 KiB。完整响应使用HTTP200,逐项标记结果。 - [HTTP入口](../../internal/transport/httpserver/tasks.go):`POST /v1/tasks:batch`,全体正文严格解析后才受理,每项正文幂等键,总请求512 KiB。完整响应使用HTTP200,逐项标记结果。
- [独立SDK](../../sdk/go/batch.go):SubmitTasks及中文字段说明,不自动生成身份、拆批或重试;校验返回数量、顺序、状态与回执归属。 - [独立SDK](../../sdk/go/batch.go):SubmitTasks及中文字段说明,不自动生成身份、拆批或重试;校验返回数量、顺序、状态与回执归属。
- [运行示例](../../sdk/go/examples/batch/main.go):两项受理、一项满额,原键核对后释放配额,仅补交被拒项并取消收尾。 - [运行示例](../../examples/batch/main.go):两项受理、一项满额,原键核对后释放配额,仅补交被拒项并取消收尾。
- [接口手册](../api/batch-tasks.md)、[场景说明](../examples/batch.md)、[开发计划](../08-development-plan.md) 同步维护。 - [接口手册](../api/batch-tasks.md)、[场景说明](../examples/batch.md)、[开发计划](../08-development-plan.md) 同步维护。
不增加数据库模型或迁移,平台仍为35个实体、289个中文注释持久化字段;不增加外键、级联或SDK数据库依赖。 不增加数据库模型或迁移,平台仍为35个实体、289个中文注释持久化字段;不增加外键、级联或SDK数据库依赖。

View File

@@ -9,7 +9,7 @@
- 取消后不延长期限、不产生后续重试;有效成功结果仍能确认,普通取消错误或失联保持未知效果。 - 取消后不延长期限、不产生后续重试;有效成功结果仍能确认,普通取消错误或失联保持未知效果。
- 明确取消结果使用 task.finish / CANCELLED;本次确认停止不能清除此前未核实的外部效果。 - 明确取消结果使用 task.finish / CANCELLED;本次确认停止不能清除此前未核实的外部效果。
- 可选择的 task.cancel 通知、Resume/Start/Renew 中的当前取消意图、独立 SDK 自动停止处理器和有界收尾。 - 可选择的 task.cancel 通知、Resume/Start/Renew 中的当前取消意图、独立 SDK 自动停止处理器和有界收尾。
- [完整取消场景](../../sdk/go/examples/cancellation/main.go)、[接口与升级说明](../api/cancellation.md) 已同步交付。 - [完整取消场景](../../examples/cancellation/main.go)、[接口与升级说明](../api/cancellation.md) 已同步交付。
- 迁移 000007 扩展取消证据;000008 移除 70 个历史外键,保留索引、唯一约束、CHECK、触发器和数据。实体数仍为 32,没有新增持久化字段。 - 迁移 000007 扩展取消证据;000008 移除 70 个历史外键,保留索引、唯一约束、CHECK、触发器和数据。实体数仍为 32,没有新增持久化字段。
- 开发规范明确禁止再引入外键。应用启动/readiness 核验迁移及零外键要求;任务、计划及 Worker 关联由服务端事务校验。 - 开发规范明确禁止再引入外键。应用启动/readiness 核验迁移及零外键要求;任务、计划及 Worker 关联由服务端事务校验。

View File

@@ -8,7 +8,7 @@
- [EventConsumer](../../sdk/go/event_consumer.go):自动心跳、指数退避重连、本地1–32个在途事件、成功后确认、ACK不明时原证明核对、处理器失败不确认、取消与有界收尾。 - [EventConsumer](../../sdk/go/event_consumer.go):自动心跳、指数退避重连、本地1–32个在途事件、成功后确认、ACK不明时原证明核对、处理器失败不确认、取消与有界收尾。
- [类型及秘密隐藏](../../sdk/go/event_types.go):ResultEvent不给业务处理器租约秘密;Grant/Proof仍可显式序列化用于受保护的存储,普通fmt隐藏敏感数据。 - [类型及秘密隐藏](../../sdk/go/event_types.go):ResultEvent不给业务处理器租约秘密;Grant/Proof仍可显式序列化用于受保护的存储,普通fmt隐藏敏感数据。
- [严格解码](../../sdk/go/event_codec.go):大小写、重复键、方向、会话、规范uint64、证明编码和事件/交付/快照关联。大整数不经float64转换。协议类WebSocket关闭按永久错误处理。 - [严格解码](../../sdk/go/event_codec.go):大小写、重复键、方向、会话、规范uint64、证明编码和事件/交付/快照关联。大整数不经float64转换。协议类WebSocket关闭按永久错误处理。
- [协议例子](../../sdk/go/examples/event-protocol/main.go):产生取消结果、读取、ACK、重连重报、验证原确认时间、暂停订阅。它只读取结果,不执行接收方业务写入。 - [协议例子](../../examples/event-protocol/main.go):产生取消结果、读取、ACK、重连重报、验证原确认时间、暂停订阅。它只读取结果,不执行接收方业务写入。
- SDK保持独立模块,无新增数据库驱动、服务端包或持久化模型。本阶段不增加迁移、外键或级联删除。 - SDK保持独立模块,无新增数据库驱动、服务端包或持久化模型。本阶段不增加迁移、外键或级联删除。
## 2. 验证环境与入口 ## 2. 验证环境与入口

View File

@@ -10,7 +10,7 @@
- 续租、取消、结果、退避及到期恢复同步维护两类许可。UNKNOWN 释放执行许可并保留核查与未知效果,旧结果不能释放后续尝试的许可。 - 续租、取消、结果、退避及到期恢复同步维护两类许可。UNKNOWN 释放执行许可并保留核查与未知效果,旧结果不能释放后续尝试的许可。
- Worker 显式协商 concurrency_keys;旧 Worker 不消费有键任务,自动 SDK 默认开启。协议 Schema、SDK 精确 uint64、尝试历史与计划模板同步支持。 - Worker 显式协商 concurrency_keys;旧 Worker 不消费有键任务,自动 SDK 默认开启。协议 Schema、SDK 精确 uint64、尝试历史与计划模板同步支持。
- [000011 迁移](../../internal/storage/mysql/migrations/000011_keyed_concurrency.up.sql) 新增四个中文注释字段,无外键。当前 33 个实体、273 个直接声明的持久化字段均有中文注释,SQL 同步 COMMENT。 - [000011 迁移](../../internal/storage/mysql/migrations/000011_keyed_concurrency.up.sql) 新增四个中文注释字段,无外键。当前 33 个实体、273 个直接声明的持久化字段均有中文注释,SQL 同步 COMMENT。
- [完整示例](../../sdk/go/examples/keyed-concurrency/main.go) 创建两个队列、两个 Worker、相同资源键,核对序号并模拟资源端拒绝旧写入。 - [完整示例](../../examples/keyed-concurrency/main.go) 创建两个队列、两个 Worker、相同资源键,核对序号并模拟资源端拒绝旧写入。
## 2. 环境与命令 ## 2. 环境与命令

View File

@@ -9,7 +9,7 @@
- 以最多 270 秒的排序优势实现优先级加速;等待超过此优势的旧任务不被不断到来的最高级新任务持续插队。没有承诺 270 秒内完成或严格 FIFO。 - 以最多 270 秒的排序优势实现优先级加速;等待超过此优势的旧任务不被不断到来的最高级新任务持续插队。没有承诺 270 秒内完成或严格 FIFO。
- [节点领取池](../../internal/dispatch/pool.go) 将原来的各连接并发轮询改为应用 → 队列 → 连接请求轮转。总并发 4、单应用在途 1、待处理加在途最多 128;每连接最多一个未完成请求。应用归属由认证后的数据库关系取得,不能按自报应用或不同命名空间分组。 - [节点领取池](../../internal/dispatch/pool.go) 将原来的各连接并发轮询改为应用 → 队列 → 连接请求轮转。总并发 4、单应用在途 1、待处理加在途最多 128;每连接最多一个未完成请求。应用归属由认证后的数据库关系取得,不能按自报应用或不同命名空间分组。
- 同命名空间/队列/精确能力的空探测在节点内合并一个周期,缓存最多 128 项;控制收发继续运行。所有任务状态、许可、预算和执行授权仍由数据库事务决定。 - 同命名空间/队列/精确能力的空探测在节点内合并一个周期,缓存最多 128 项;控制收发继续运行。所有任务状态、许可、预算和执行授权仍由数据库事务决定。
- [可运行示例](../../sdk/go/examples/priority/main.go)、协议 Schema、接口与 SDK 文档同步更新。当前仍为 33 个实体,274 个直接声明持久化字段全部有中文注释,最终数据库外键为零。 - [可运行示例](../../examples/priority/main.go)、协议 Schema、接口与 SDK 文档同步更新。当前仍为 33 个实体,274 个直接声明持久化字段全部有中文注释,最终数据库外键为零。
## 2. 环境和执行 ## 2. 环境和执行

View File

@@ -12,7 +12,7 @@
- 计划补跑受相同积压上限限制,保留未受理的原触发点;释放空间后按冻结漏跑策略接续。 - 计划补跑受相同积压上限限制,保留未受理的原触发点;释放空间后按冻结漏跑策略接续。
- 迁移 000009 增加四个队列字段并回填既有未终结任务,Go/SQL 均有中文说明,无数据库外键。 - 迁移 000009 增加四个队列字段并回填既有未终结任务,Go/SQL 均有中文说明,无数据库外键。
- 源码核对 257 个直接声明的持久化字段均有中文注释;实体仍为 32 个。 - 源码核对 257 个直接声明的持久化字段均有中文注释;实体仍为 32 个。
- [队列接口与完整 SDK 场景](../api/queues.md)、[resources 示例](../../sdk/go/examples/resources/main.go) 同步交付。 - [队列接口与完整 SDK 场景](../api/queues.md)、[resources 示例](../../examples/resources/main.go) 同步交付。
## 2. 环境及执行结果 ## 2. 环境及执行结果

View File

@@ -11,7 +11,7 @@
- 每节点 128 条事件连接;异步领取池 4 个全局在途、同应用 1 个在途、等待加在途总量 128,按认证应用及订阅轮转。控制收发不被同连接的慢领取阻塞。连接容量仍由持久化租约校验。 - 每节点 128 条事件连接;异步领取池 4 个全局在途、同应用 1 个在途、等待加在途总量 128,按认证应用及订阅轮转。控制收发不被同连接的慢领取阻塞。连接容量仍由持久化租约校验。
- [严格解码](../../internal/transport/httpserver/event_codec.go) 与 [公开 Schema](../../protocol/eventsv1/events.schema.json):方向、必填、字段精确大小写、规范 uint64、证明格式和消息大小;JSON 重复键、伪造响应字段或错误会话被拒绝。 - [严格解码](../../internal/transport/httpserver/event_codec.go) 与 [公开 Schema](../../protocol/eventsv1/events.schema.json):方向、必填、字段精确大小写、规范 uint64、证明格式和消息大小;JSON 重复键、伪造响应字段或错误会话被拒绝。
- [管理 SDK](../../sdk/go/subscriptions.go) 与 [独立 DTO](../../sdk/go/subscription_types.go):七个管理/查询方法及类型,保留大整数和显式布尔控制,不依赖服务端或数据库包。 - [管理 SDK](../../sdk/go/subscriptions.go) 与 [独立 DTO](../../sdk/go/subscription_types.go):七个管理/查询方法及类型,保留大整数和显式布尔控制,不依赖服务端或数据库包。
- [完整管理例子](../../sdk/go/examples/subscriptions/main.go) 已纳入统一隔离环境脚本。原始 WSS 测试辅助代码不作为正式消费 SDK 对外提供。 - [完整管理例子](../../examples/subscriptions/main.go) 已纳入统一隔离环境脚本。原始 WSS 测试辅助代码不作为正式消费 SDK 对外提供。
## 2. 验证环境与结果 ## 2. 验证环境与结果

View File

@@ -10,7 +10,7 @@
- 抖动退避写入数据库 available_at;与尝试结果、许可释放、事件、结果审计及操作回执原子提交。后台回收保留含节点身份与决策的事件。 - 抖动退避写入数据库 available_at;与尝试结果、许可释放、事件、结果审计及操作回执原子提交。后台回收保留含节点身份与决策的事件。
- 结果换消息身份重报也取原已应用回执;过滤早到的证据回执,避免借用后续尝试状态。 - 结果换消息身份重报也取原已应用回执;过滤早到的证据回执,避免借用后续尝试状态。
- 前向迁移 000005 增加三个中文注释字段和结果回执索引;实体仍为 32 个,旧迁移未改动。 - 前向迁移 000005 增加三个中文注释字段和结果回执索引;实体仍为 32 个,旧迁移未改动。
- 同步独立 SDK、Worker Schema、查询字段、[接口手册](../api/retries.md) 与 [完整示例](../../sdk/go/examples/retry/main.go)。 - 同步独立 SDK、Worker Schema、查询字段、[接口手册](../api/retries.md) 与 [完整示例](../../examples/retry/main.go)。
## 2. 环境与执行命令 ## 2. 环境与执行命令

View File

@@ -10,7 +10,7 @@
- SKIP / COALESCE / CATCH_UP 漏跑策略与 PARALLEL / SERIAL / SKIP 重叠策略;明确补偿窗口、延迟容差、批量和扫描间隔。 - SKIP / COALESCE / CATCH_UP 漏跑策略与 PARALLEL / SERIAL / SKIP 重叠策略;明确补偿窗口、延迟容差、批量和扫描间隔。
- 发布新版本保留旧生效边界前的积压;跳过和合并范围不越过版本边界。已产生任务保留当时模板。 - 发布新版本保留旧生效边界前的积压;跳过和合并范围不越过版本边界。已产生任务保留当时模板。
- 多节点用数据库锁与唯一触发身份竞争;触发决定、对应任务、事件及进度一起提交。 - 多节点用数据库锁与唯一触发身份竞争;触发决定、对应任务、事件及进度一起提交。
- 实际 orbit 命令持续扫描,独立 SDK 与 [完整周期快照示例](../../sdk/go/examples/schedules/main.go) 同步交付。 - 实际 orbit 命令持续扫描,独立 SDK 与 [完整周期快照示例](../../examples/schedules/main.go) 同步交付。
- 迁移 000006 增加运行字段与索引,实体仍为 32 个;新模型字段及 SQL COMMENT 均为中文;源码核对 32 个持久化模型、253 个直接声明的持久化字段均有中文说明。 - 迁移 000006 增加运行字段与索引,实体仍为 32 个;新模型字段及 SQL COMMENT 均为中文;源码核对 32 个持久化模型、253 个直接声明的持久化字段均有中文说明。
完整字段、权限、状态与示例见 [接口手册](../api/schedules.md)。 完整字段、权限、状态与示例见 [接口手册](../api/schedules.md)。

View File

@@ -8,7 +8,7 @@
- [查询存储](../../internal/storage/mysql/task_query.go):固定四种索引分支、参数化SQL、创建时间/ID游标分页,v2摘要绑定全部筛选,旧游标只兼容原队列/状态查询。 - [查询存储](../../internal/storage/mysql/task_query.go):固定四种索引分支、参数化SQL、创建时间/ID游标分页,v2摘要绑定全部筛选,旧游标只兼容原队列/状态查询。
- [HTTP入口](../../internal/transport/httpserver/tasks.go)与[独立SDK](../../sdk/go/task_query.go):URL编码、UTC规范化、显式空参数与未知参数拒绝,SDK无数据库依赖。 - [HTTP入口](../../internal/transport/httpserver/tasks.go)与[独立SDK](../../sdk/go/task_query.go):URL编码、UTC规范化、显式空参数与未知参数拒绝,SDK无数据库依赖。
- [迁移000016](../../internal/storage/mysql/migrations/000016_task_query_filters.up.sql):business_key使用精确NO PAD二进制排序,增加两种队列业务键索引,中文字段含义同步。无新增模型字段、无外键/级联,仍为35个模型、289个持久化字段。 - [迁移000016](../../internal/storage/mysql/migrations/000016_task_query_filters.up.sql):business_key使用精确NO PAD二进制排序,增加两种队列业务键索引,中文字段含义同步。无新增模型字段、无外键/级联,仍为35个模型、289个持久化字段。
- [接口手册](../api/task-queries.md)、[完整示例说明](../examples/task-query.md)及[源码](../../sdk/go/examples/task-query/main.go)。 - [接口手册](../api/task-queries.md)、[完整示例说明](../examples/task-query.md)及[源码](../../examples/task-query/main.go)。
## 2. 真实数据库验证 ## 2. 真实数据库验证

View File

@@ -7,7 +7,7 @@
- [服务契约](../../pulse/service/recovery.go):显式历史执行结束/安全重试声明、原因、证据、版本及预算校验。 - [服务契约](../../pulse/service/recovery.go):显式历史执行结束/安全重试声明、原因、证据、版本及预算校验。
- [数据库事务](../../internal/storage/mysql/task_recovery.go):NEEDS_REVIEW核查为SUCCEEDED/FAILED,原尝试保留;独立FAILED/CANCELLED任务生成retry_of关联后继,原任务不改写。 - [数据库事务](../../internal/storage/mysql/task_recovery.go):NEEDS_REVIEW核查为SUCCEEDED/FAILED,原尝试保留;独立FAILED/CANCELLED任务生成retry_of关联后继,原任务不改写。
- [审计查询](../../internal/storage/mysql/task_operations.go):专门权限与父资源范围,摘要游标分页、详情原因和证据,真实凭据身份。 - [审计查询](../../internal/storage/mysql/task_operations.go):专门权限与父资源范围,摘要游标分页、详情原因和证据,真实凭据身份。
- [Go SDK](../../sdk/go/recovery.go)、[接口手册](../api/task-recovery.md)、[完整运行场景](../examples/recovery.md)及[源码](../../sdk/go/examples/recovery/main.go)。 - [Go SDK](../../sdk/go/recovery.go)、[接口手册](../api/task-recovery.md)、[完整运行场景](../examples/recovery.md)及[源码](../../examples/recovery/main.go)。
- [迁移000015](../../internal/storage/mysql/migrations/000015_task_manual_recovery.up.sql):现有RetryOf字段中文语义、同父后继唯一索引与禁止自身关联CHECK。35个模型、289个持久化字段,无新增字段,无外键/级联。 - [迁移000015](../../internal/storage/mysql/migrations/000015_task_manual_recovery.up.sql):现有RetryOf字段中文语义、同父后继唯一索引与禁止自身关联CHECK。35个模型、289个持久化字段,无新增字段,无外键/级联。
## 2. 已覆盖的数据库与协议场景 ## 2. 已覆盖的数据库与协议场景

View File

@@ -7,7 +7,7 @@
- [服务模型](../../pulse/service/source.go)与[存储查询](../../internal/storage/mysql/task_source.go):DIRECT、MANUAL_RETRY、SCHEDULE三类来源;计划ID、触发记录、冻结版本及合并范围;人工重试仅一跳父任务。 - [服务模型](../../pulse/service/source.go)与[存储查询](../../internal/storage/mysql/task_source.go):DIRECT、MANUAL_RETRY、SCHEDULE三类来源;计划ID、触发记录、冻结版本及合并范围;人工重试仅一跳父任务。
- [HTTP路由](../../internal/transport/httpserver/history.go)提供GET /v1/tasks/{task_id}/source,沿用tasks:read和队列范围,拒绝查询参数。 - [HTTP路由](../../internal/transport/httpserver/history.go)提供GET /v1/tasks/{task_id}/source,沿用tasks:read和队列范围,拒绝查询参数。
- [独立SDK](../../sdk/go/task_source.go)验证响应ID、类型组合、版本和时间,保留uint64精度;没有数据库依赖或自动重试。 - [独立SDK](../../sdk/go/task_source.go)验证响应ID、类型组合、版本和时间,保留uint64精度;没有数据库依赖或自动重试。
- [接口手册](../api/task-source.md)、[普通提交](../../sdk/go/examples/tasks/main.go)、[计划](../../sdk/go/examples/schedules/main.go)及[人工恢复](../../sdk/go/examples/recovery/main.go)同步提供调用与输出。 - [接口手册](../api/task-source.md)、[普通提交](../../examples/tasks/main.go)、[计划](../../examples/schedules/main.go)及[人工恢复](../../examples/recovery/main.go)同步提供调用与输出。
来源独立读取,不改变Task/TaskSummary及Worker协议,不在派发路径增加关联查询。复用现有(namespace_id,task_id)触发唯一索引及计划版本键,不新增迁移、索引或持久化字段;平台仍为35个实体、289个中文注释字段。新只读结构的字段也均有中文说明。 来源独立读取,不改变Task/TaskSummary及Worker协议,不在派发路径增加关联查询。复用现有(namespace_id,task_id)触发唯一索引及计划版本键,不新增迁移、索引或持久化字段;平台仍为35个实体、289个中文注释字段。新只读结构的字段也均有中文说明。

View File

@@ -11,7 +11,7 @@
| 立即、相对延迟、指定时间提交 | 立即受理、数据库时间计算delay_ms、绝对available_at;[HTTP事务用例](../../internal/storage/mysql/task_integration_test.go)核对同键并发、相对时长、非法组合与批量;[SDK真实执行](../../sdk/go/task_delay_integration_test.go)核对数据库创建/开始时间不早于保存的执行时间 | | 立即、相对延迟、指定时间提交 | 立即受理、数据库时间计算delay_ms、绝对available_at;[HTTP事务用例](../../internal/storage/mysql/task_integration_test.go)核对同键并发、相对时长、非法组合与批量;[SDK真实执行](../../sdk/go/task_delay_integration_test.go)核对数据库创建/开始时间不早于保存的执行时间 |
| 批量受理、逐项恢复 | 最多32项/512 KiB,单项事务和身份复用,区分明确失败/未知/未尝试;[批量报告](phase-3-batch-tasks.md)记录部分已提交后的真实HTTP回执丢失及原键补交 | | 批量受理、逐项恢复 | 最多32项/512 KiB,单项事务和身份复用,区分明确失败/未知/未尝试;[批量报告](phase-3-batch-tasks.md)记录部分已提交后的真实HTTP回执丢失及原键补交 |
| 幂等及不可变参数/策略 | 任务、身份回执、事件与审计同事务;同语义原回执、变更冲突;[任务用例](../../internal/storage/mysql/task_integration_test.go)核对16并发只创建一次和精确数字;新增可选字段的[旧摘要兼容](../../internal/storage/mysql/task_delay_test.go) | | 幂等及不可变参数/策略 | 任务、身份回执、事件与审计同事务;同语义原回执、变更冲突;[任务用例](../../internal/storage/mysql/task_integration_test.go)核对16并发只创建一次和精确数字;新增可选字段的[旧摘要兼容](../../internal/storage/mysql/task_delay_test.go) |
| 改参数形成关联新任务 | 新提交身份和相同business_key,旧输入保持;[查询示例](../../sdk/go/examples/task-query/main.go)分别读取text/json任务核对输入。该关联不等于业务去重或retry_of,原任务需调用方决定如何处理 | | 改参数形成关联新任务 | 新提交身份和相同business_key,旧输入保持;[查询示例](../../examples/task-query/main.go)分别读取text/json任务核对输入。该关联不等于业务去重或retry_of,原任务需调用方决定如何处理 |
| 单次/总时限、最晚开始、安全重试 | 冻结策略、有限退避及未知效果;[决策](../../pulse/retry/decision_test.go)、[真实事务](../../internal/storage/mysql/worker_retry_integration_test.go)核对预算/回滚/迟到;[全停恢复](phase-3-delay-recovery.md)保留退避、次数和截止,过期不补发 | | 单次/总时限、最晚开始、安全重试 | 冻结策略、有限退避及未知效果;[决策](../../pulse/retry/decision_test.go)、[真实事务](../../internal/storage/mysql/worker_retry_integration_test.go)核对预算/回滚/迟到;[全停恢复](phase-3-delay-recovery.md)保留退避、次数和截止,过期不补发 |
| 等待/运行取消 | 持久化意图、预占阻止开始、运行收集结果、未知效果仍核查;[取消事务](../../internal/storage/mysql/worker_cancel_integration_test.go)验证开始竞争/回滚,[取消报告](phase-3-cancellation.md)包含自动SDK通知、丢通知及不协作处理器 | | 等待/运行取消 | 持久化意图、预占阻止开始、运行收集结果、未知效果仍核查;[取消事务](../../internal/storage/mysql/worker_cancel_integration_test.go)验证开始竞争/回滚,[取消报告](phase-3-cancellation.md)包含自动SDK通知、丢通知及不协作处理器 |
| 人工核查与重试 | 专门权限、版本、原因/证据、安全声明;核查不改旧尝试,人工重试创建唯一直接后继;[恢复用例](../../internal/storage/mysql/task_recovery_integration_test.go)验证竞争、审计失败回滚、原输入/结果保留及管理所有权;[接口/故障报告](phase-3-task-recovery.md) | | 人工核查与重试 | 专门权限、版本、原因/证据、安全声明;核查不改旧尝试,人工重试创建唯一直接后继;[恢复用例](../../internal/storage/mysql/task_recovery_integration_test.go)验证竞争、审计失败回滚、原输入/结果保留及管理所有权;[接口/故障报告](phase-3-task-recovery.md) |

View File

@@ -35,7 +35,7 @@
3. 已知失败步骤与并行信号等待 → RearmWorkflowWait第二代,原截止不变 → 旧代次信号被拒绝 → RetryWorkflowStep只保留一次剩余尝试 → 解除核查 → 新任务和新代次信号完成流程。 3. 已知失败步骤与并行信号等待 → RearmWorkflowWait第二代,原截止不变 → 旧代次信号被拒绝 → RetryWorkflowStep只保留一次剩余尝试 → 解除核查 → 新任务和新代次信号完成流程。
4. 查询UNKNOWN → 核查为SUCCEEDED/PENDING → 原结果消费 → ContinueWorkflowPoll → ContinueWorkflow → 只创建第二业务轮并最终DONE;查询总截止不变。 4. 查询UNKNOWN → 核查为SUCCEEDED/PENDING → 原结果消费 → ContinueWorkflowPoll → ContinueWorkflow → 只创建第二业务轮并最终DONE;查询总截止不变。
实现和证据:[公共路由](../../internal/transport/httpserver/workflows.go)、[严格JSON测试](../../internal/transport/httpserver/workflows_test.go)、[初始化范围测试](../../internal/storage/mysql/workflow_bootstrap_integration_test.go)、[当前详情及审计范围测试](../../internal/storage/mysql/workflow_details_integration_test.go)、[独立SDK场景](../../sdk/go/workflow_instances_integration_test.go)、[示例源码](../../sdk/go/examples/workflow/main.go)。完整复现入口是[隔离MySQL脚本](../../scripts/test-mysql.sh),跳过的环境依赖测试不算通过。 实现和证据:[公共路由](../../internal/transport/httpserver/workflows.go)、[严格JSON测试](../../internal/transport/httpserver/workflows_test.go)、[初始化范围测试](../../internal/storage/mysql/workflow_bootstrap_integration_test.go)、[当前详情及审计范围测试](../../internal/storage/mysql/workflow_details_integration_test.go)、[独立SDK场景](../../sdk/go/workflow_instances_integration_test.go)、[示例源码](../../examples/workflow/main.go)。完整复现入口是[隔离MySQL脚本](../../scripts/test-mysql.sh),跳过的环境依赖测试不算通过。
## 剩余交付 ## 剩余交付

View File

@@ -10,7 +10,7 @@
- 000024只新增派生范围表、不可更新触发器及7个复合索引;回填遍历DSL步骤块,保留原版本/实例。最终表结构外键为0,无级联。当前36个模型、311个直接持久化字段有中文注释。 - 000024只新增派生范围表、不可更新触发器及7个复合索引;回填遍历DSL步骤块,保留原版本/实例。最终表结构外键为0,无级联。当前36个模型、311个直接持久化字段有中文注释。
- HTTP严格解析参数;SDK与服务端保持独立module。独立示例发布等待流程、验证精确分页、取消结清,不需Worker,也不模拟业务成功。 - HTTP严格解析参数;SDK与服务端保持独立module。独立示例发布等待流程、验证精确分页、取消结清,不需Worker,也不模拟业务成功。
接口:[查询手册](../api/workflow-queries.md)。示例:[运行说明](../examples/workflow-query.md)及[源码](../../sdk/go/examples/workflow-query/main.go)。 接口:[查询手册](../api/workflow-queries.md)。示例:[运行说明](../examples/workflow-query.md)及[源码](../../examples/workflow-query/main.go)。
## 环境与命令 ## 环境与命令

View File

@@ -25,7 +25,7 @@
专项验证固定版本发布后不变、仅有单队列tasks:read也能查当前任务来源、读取完整流程/定义仍拒绝、跨命名空间/队列拒绝;逐项注入错误所有者、门控、处理器版本、激活所属流程/步骤、任务反向引用、步骤类型、固定版本及策略错误;测试同时出现TASK/POLL关联、POLL父任务错误轮次及所有者丢失。真实恢复链验证业务第1轮→恢复第1轮→第2轮→再次恢复第2轮,激活与业务轮分别计数,原历史可读。 专项验证固定版本发布后不变、仅有单队列tasks:read也能查当前任务来源、读取完整流程/定义仍拒绝、跨命名空间/队列拒绝;逐项注入错误所有者、门控、处理器版本、激活所属流程/步骤、任务反向引用、步骤类型、固定版本及策略错误;测试同时出现TASK/POLL关联、POLL父任务错误轮次及所有者丢失。真实恢复链验证业务第1轮→恢复第1轮→第2轮→再次恢复第2轮,激活与业务轮分别计数,原历史可读。
源码:[来源存储](../../internal/storage/mysql/task_workflow_source.go)、[关联损坏及权限测试](../../internal/storage/mysql/task_workflow_source_integration_test.go)、[TASK恢复](../../internal/storage/mysql/workflow_recovery_integration_test.go)、[POLL恢复](../../internal/storage/mysql/workflow_poll_recovery_integration_test.go)、[SDK协议验证](../../sdk/go/task_source_test.go)、[真实SDK链路](../../sdk/go/workflow_instances_integration_test.go)、[运行例子](../../sdk/go/examples/workflow/main.go)。完整复现入口:`make integration`,见[隔离脚本](../../scripts/test-mysql.sh)。 源码:[来源存储](../../internal/storage/mysql/task_workflow_source.go)、[关联损坏及权限测试](../../internal/storage/mysql/task_workflow_source_integration_test.go)、[TASK恢复](../../internal/storage/mysql/workflow_recovery_integration_test.go)、[POLL恢复](../../internal/storage/mysql/workflow_poll_recovery_integration_test.go)、[SDK协议验证](../../sdk/go/task_source_test.go)、[真实SDK链路](../../sdk/go/workflow_instances_integration_test.go)、[运行例子](../../examples/workflow/main.go)。完整复现入口:`make integration`,见[隔离脚本](../../scripts/test-mysql.sh)。
## 继续交付 ## 继续交付

View File

@@ -1,5 +1,7 @@
# P6:凭据操作与安全轮换 # P6:凭据操作与安全轮换
本报告记录当时的立即换证语义;后续长期凭据和双 Token 过渡已在[增量报告](credential-overlap.md)单独说明。
日期:2026-09-19。本文只记录管理凭据操作的已实现边界,不把凭据功能等同于 P6 全部生产验收。 日期:2026-09-19。本文只记录管理凭据操作的已实现边界,不把凭据功能等同于 P6 全部生产验收。
## 已实现行为 ## 已实现行为

View File

@@ -4,7 +4,7 @@
## 实现内容 ## 实现内容
- 新增 [`sdk/go/examples/file-conversion`](../../sdk/go/examples/file-conversion/main.go):提交两行 CSV 快照,由版本化 `file.convert.csv-json` Worker 转成 JSON 结果。 - 新增 [`examples/file-conversion`](../../examples/file-conversion/main.go):提交两行 CSV 快照,由版本化 `file.convert.csv-json` Worker 转成 JSON 结果。
- 处理器只读取任务输入和执行上下文,使用稳定提交键;同一个运行身份重复提交不创建第二个任务。 - 处理器只读取任务输入和执行上下文,使用稳定提交键;同一个运行身份重复提交不创建第二个任务。
- 结果包含输出文件名、格式、转换正文和行数;输入标题重复、行列数不匹配或格式不支持时返回固定 `INVALID_FILE`,不把原始异常正文写入结果。 - 结果包含输出文件名、格式、转换正文和行数;输入标题重复、行列数不匹配或格式不支持时返回固定 `INVALID_FILE`,不把原始异常正文写入结果。
- 示例结束前等待 Worker 排空,任务与审计历史保留;单元测试覆盖正常 CSV、重复标题和列数错误。 - 示例结束前等待 Worker 排空,任务与审计历史保留;单元测试覆盖正常 CSV、重复标题和列数错误。

View File

@@ -10,7 +10,7 @@ ORBIT_COMPAT_OLD_COMMIT=a50d5fa ./scripts/test-historical-sdk-compatibility.sh
make mysql-compatibility make mysql-compatibility
``` ```
脚本使用 Go 1.27.1 容器构建历史与当前的 `orbit`、`orbit-migrate`、`orbit-admin`,使用一次性 MySQL 8.4 数据库分别初始化两套 schema,再启动真实 HTTP 服务运行 `sdk/go/examples/tasks`。任务提交、重复幂等、查询、分页和取消都通过真实服务完成;数据库、容器、临时凭据和二进制在退出时清理。 脚本使用 Go 1.27.1 容器构建历史与当前的 `orbit`、`orbit-migrate`、`orbit-admin`,使用一次性 MySQL 8.4 数据库分别初始化两套 schema,再启动真实 HTTP 服务运行 `examples/tasks`。任务提交、重复幂等、查询、分页和取消都通过真实服务完成;数据库、容器、临时凭据和二进制在退出时清理。
## 实际结果 ## 实际结果

View File

@@ -0,0 +1,39 @@
# 通用资源退役与接入体验验收
日期:2026-09-27。范围:平台、Go SDK、控制台及通用示例;不包含接入方业务处理器、支付渠道或业务数据变更。
## 实现
迁移 000034 增加队列/订阅退役时间及订阅提交水位、活动索引和约束,无外键。退役、不可变审计、原操作回执同事务;新工作不能复用退役队列,已完成流程的原启动回执仍可重放。订阅结清释放名额,暂停仍占名额,不删除或伪造确认历史。
控制台增加明确队列选择/记忆、暂停/退役状态和名额统计,提供带原因和版本的退役入口。凭据未补存时统一提示补存,不能静默换队列复制。没有修改任何现有应用的 Token、权限或过渡期。
## 回归结果
- `make test`、`make vet build`、`make sdk-check protocol-check docs-check`、JavaScript 语法检查全部退出 0;七个模块的基础竞态回归与 SDK 独立构建通过。
- `make integration` 最终完整重跑退出 0:真实 MySQL 存储/迁移、HTTP、SDK、Worker/事件/流程进程故障、Outbox 与 HTTP 宿主链路通过。SDK 生命周期示例实际输出 `retired=true history_preserved=true subscription_replay=true`。
- 新增真实 MySQL 8 项场景通过:未物化/租约/耗尽交付保护、64 名额释放且历史保留、任务/订阅依赖、计划恢复阻止、等待流程保护、完成流程原回执和历史、真实锁竞争、审计失败回滚。保留零外键断言。
- `make console-e2e` 退出 0:跨应用管理员范围、CSRF、退役幂等、名额变化、历史读取,以及原登录/任务/计划/归档链路通过。
- 初轮完整 MySQL 回归发现两处旧升级夹具未计入新约束/索引,修正后完整重跑通过:旧结构还原时移除 000034 新字段与约束;原索引对比排除新加活动索引。没有放宽原索引、数据和零外键断言。
- 当前协议契约检查通过,未重跑历史版本服务端与历史 SDK 的双向兼容矩阵;不能把本次结果等同于重新验收所有历史组合。
## 本地部署与页面核对
持久 Compose 环境已在备份数据库和凭据保管密钥后升级到 000034,迁移及零外键核验成功,readiness 通过。原应用、凭据和过渡截止保持。部署脚本同时修正了重复构建时的版本时间戳,`/version` 不再沿用首次初始化时间。
浏览器已验证:多队列时不默认第一条,手动选择后刷新保留;暂停队列有标签;历史 Token 未补存时说明一致;队列还有订阅时显示中文阻止原因。使用独占空订阅验证了实际退役提交、退役状态、详情和历史仍可读,且不再出现恢复入口;活动名额从 7/64 回到 6/64。随后从页面退役对应空队列,配置选择中标记已退役并禁选。没有对接入方既有队列或凭据执行退役、轮换或提前结束过渡。
## 版本交付
`main` 与两个不可变标签 `v0.1.2`、`sdk/go/v0.1.2` 已原子推送到远端;标签代码提交为 `7b6f3ac60c0cf14113ee2bfc79de136ac05ef0aa`。Outbox 没有代码改动,继续使用 `adapters/outbox/mysql/v0.1.1`。
仓库外新模块使用空模块缓存、`GOWORK=off` 安装远端 SDK v0.1.2 与 Outbox v0.1.1,没有本地 `replace`。实际通过依赖解析、`go vet`、构建和 `go mod verify`,并连接本地真实平台执行新队列/订阅创建、订阅退役和原键重报、队列退役,输出 `retired=true history_preserved=true subscription_replay=true`。
本地运行 `v0.1.2-local` / `7b6f3ac`,构建时间为 `2026-09-27T06:50:22Z`;readiness 通过,HTTP/Worker/Event 仍为协议 1。后续报告提交只补验收记录,不改变标签代码或已部署二进制。
## 明确边界
不提供强制忽略结果或批量硬删除。历史未确认/未知效果须先核查;没有消费者时需要恢复消费并确认积压。资源名称不回收。归档仍按已有配置导出并保留源记录,退役不缩减物理存储。
新服务端禁止与忽略退役状态的旧写节点混跑。旧 SDK 既有 API 兼容;新的退役方法使用 v0.1.2。隔离回归不代替目标生产环境的容量、跨故障域或真实业务验收。

View File

@@ -0,0 +1,65 @@
# v0.1.1:统一示例与正式版本发布
日期:2026-09-24。目标:以 `main` 交付代码,使用固定版本安装 SDK/Outbox,将功能说明和接入入口集中到根 README。
## 内容
- 24 个轻量 SDK 示例迁至根 examples module;与原有三个业务数据库工程一起形成 27 个独立场景目录。
- 每个目录补充 README,根 README 列出功能、准备条件、初始化管理员、调用方式、预期结果、配置及运维入口。
- 工作区、7 个模块的构建回归、MySQL/控制台/历史兼容脚本同步调整路径;历史版本 checkout 仍使用其原目录。
- 公共 SDK 生产代码没有改动;公共 MySQL Outbox 核心沿用[已经验收的实现](outbox-http-integration.md)。数据库结构没有因本次目录整理变化。
## 本次验证
本地检查与发布后远端安装均已完成,结果如下:
| 检查 | 结果 |
| --- | --- |
| 7 模块 `make test vet build` | 通过,退出 0 |
| `make sdk-check protocol-check docs-check` | 通过;SDK 5 个包、禁止依赖为 0;193 份 Markdown 本地链接有效 |
| `make integration` | 通过,退出 0;真实 MySQL、27 个示例场景、事务/HTTP 回执丢失、进程强杀及多节点恢复 |
| `make console-e2e` | 通过;登录/保护路由、Worker/重试/计划、保留策略/周期归档作业、离线核验和退出登录 |
| 历史任务 API 双向 smoke | 通过;当前 SDK 对 a50d5fa 服务端、a50d5fa SDK 对当前服务端 |
| 远端 main 与三组标签 | 原子推送成功,默认分支 main;三组标签均指向发布提交 81e56bd633cfe9f7669b4243dee5d7683e5f6697 |
| 仓库外固定版本安装、构建、HTTP smoke 与校验和 | 空模块缓存、GOWORK=off、无 replace;两个模块精确解析为 v0.1.1,全部退出 0 |
## 版本约定
服务端 `v0.1.1`、SDK `sdk/go/v0.1.1`、Outbox `adapters/outbox/mysql/v0.1.1` 对齐同一个发布提交。既有 v0.1.0 标签保留,不强推或覆盖。
轻量示例及适配包 go.mod 保留 SDK 最低兼容依赖 v0.1.0;在仓库中通过 go.work 测试本地 SDK,在 GOWORK=off 下验证已发布最低依赖。业务安装当前 v0.1.1,不依赖本地 replace。三个业务示例中的 replace 只用于仓库内开发联调。
## 边界
上述检查验证示例迁移、当前平台链路和远端发布,不等同于目标生产容量或跨故障域验收。历史 API smoke 不冒充全协议跨标签矩阵,具体矩阵见[兼容说明](../sdk/compatibility.md)。归档继续保留源数据,不承诺源数据删除或其他数据库适配。
## 远端发布证据
发布提交为 `81e56bd633cfe9f7669b4243dee5d7683e5f6697`。通过 `git ls-remote --symref origin` 核对默认分支为 main,平台/SDK/Outbox 三组标签解引用到同一提交。随后仅补充本验证记录,既有标签不移动。远端 main 的根 README 与 examples/README 原文逐字节核对一致。
在仓库外新建 `example.com/orbit-release-consumer`,使用全新 GOPATH/GOMODCACHE、`GOWORK=off`,执行:
```sh
go get git.yuntuo.hk/k2safe/orbit/sdk/go@v0.1.1 git.yuntuo.hk/k2safe/orbit/adapters/outbox/mysql@v0.1.1
go mod tidy
go build ./...
go run .
go mod verify
```
测试程序通过远端 SDK 调用本地 httptest 服务的健康接口,并读取远端 Outbox SchemaSQL 核对表名及零外键;这一步验证远端包安装与可用性,真实数据库事务/HTTP 业务链路由上方全量回归覆盖。实际输出:
```text
remote_sdk_http_smoke=passed outbox_schema_smoke=passed
all modules verified
remote_versions=v0.1.1 no_replace=true checksum_verification=enabled
```
验证进程使用 `GOPROXY=https://goproxy.cn,direct`,仅在该进程沿用主机已有网络代理;`GOSUMDB=sum.golang.org` 保持开启,未关闭校验和、未设置私有模块例外、未修改全局 Go/Git 配置。解析结果:
```text
git.yuntuo.hk/k2safe/orbit/sdk/go v0.1.1 h1:xikN6Frz7HJsHdh4e3iHG9sX4cJNlRjKh0Wn/ApN3XI=
git.yuntuo.hk/k2safe/orbit/sdk/go v0.1.1/go.mod h1:9KlMW7Gy+EGaDoEwr3wHHFY47mnAymSfYeQpMS7h4ag=
git.yuntuo.hk/k2safe/orbit/adapters/outbox/mysql v0.1.1 h1:oqRfqtAq6Q1CWss4RFH1jnGu8S+2xr5e+QmeC5zfMPE=
git.yuntuo.hk/k2safe/orbit/adapters/outbox/mysql v0.1.1/go.mod h1:G+8DIXGFFssSeQ9T1HahnKUyoKNlF2GQDB21ENO3xqk=
```

View File

@@ -1,6 +1,6 @@
# Go SDK 接入说明 # Go SDK 接入说明
已实现健康查询、任务单项与[批量提交](../api/batch-tasks.md)/查询/分页/待执行取消、队列创建/查询、[自动 Worker](worker-runtime.md)、[Worker 底层协议 SDK](worker.md) 和 [执行历史查询](../api/execution-history.md)。[人工核查与重试](../api/task-recovery.md) 已提供 ReviewTask、RetryTask 与任务操作审计查询。[安全重试](../api/retries.md) 已提供有限策略、WorkerFailure.Retryable、历史查询及完整例子。[计划调度](../api/schedules.md) 已支持创建、查询、版本发布、暂停/恢复、触发历史与完整示例。[订阅管理](../api/subscriptions.md) 已支持创建、查询、暂停恢复、交付历史与人工重试;[事件消费 SDK](event-consumer.md) 已支持连接、自动心跳、重连与确认。[流程定义发布](../api/workflow-definitions.md)、[实例/控制/信号/操作审计](../api/workflows.md)及[六类人工恢复](../api/workflow-recovery.md)已提供独立SDK;完整历史与更多场景按[开发计划](../08-development-plan.md)继续实现。 已实现健康查询、任务单项与[批量提交](../api/batch-tasks.md)/查询/分页/待执行取消、队列创建/查询、[自动 Worker](worker-runtime.md)、[Worker 底层协议 SDK](worker.md) 和 [执行历史查询](../api/execution-history.md)。[人工核查与重试](../api/task-recovery.md) 已提供 ReviewTask、RetryTask 与任务操作审计查询。[安全重试](../api/retries.md) 已提供有限策略、WorkerFailure.Retryable、历史查询及完整例子。[计划调度](../api/schedules.md) 已支持创建、查询、版本发布、暂停/恢复、触发历史与完整示例。[订阅管理](../api/subscriptions.md) 已支持创建、查询、暂停恢复、交付历史与人工重试;[事件消费 SDK](event-consumer.md) 已支持连接、自动心跳、重连与确认。[流程定义发布](../api/workflow-definitions.md)、[实例/控制/信号/操作审计](../api/workflows.md)及[六类人工恢复](../api/workflow-recovery.md)已提供独立SDK;历史、查询、轮询与恢复均有[可运行示例](../../examples/README.md)。
生产接入推荐按[生产接入闭环](production-integration.md)执行:业务 Outbox 持久化幂等身份,SDK 负责 HTTP 受理和查询,Event WebSocket 负责可靠通知,业务 Inbox 负责去重和确认;网络结果不明时始终保留原键核对。 生产接入推荐按[生产接入闭环](production-integration.md)执行:业务 Outbox 持久化幂等身份,SDK 负责 HTTP 受理和查询,Event WebSocket 负责可靠通知,业务 Inbox 负责去重和确认;网络结果不明时始终保留原键核对。
@@ -29,11 +29,11 @@ go run ./cmd/orbit
另开终端,从仓库根目录执行: 另开终端,从仓库根目录执行:
```sh ```sh
cd sdk/go cd examples
ORBIT_URL=http://127.0.0.1:8080 go run ./examples/health ORBIT_URL=http://127.0.0.1:8080 go run ./health
ORBIT_URL=http://127.0.0.1:8080 \ ORBIT_URL=http://127.0.0.1:8080 \
ORBIT_CREDENTIALS_FILE=../../.local/development.credentials.json \ ORBIT_CREDENTIALS_FILE=../.local/development.credentials.json \
go run ./examples/tasks go run ./tasks
``` ```
预期输出,task 为每次运行生成的实际 ID: 预期输出,task 为每次运行生成的实际 ID:
@@ -46,11 +46,11 @@ task=<32位任务ID> duplicate=true listed=1 final_state=CANCELLED revision=2
重复运行示例会新建一个独立任务并取消它,listed 数量可能增加,最多显示当前页 10 条。数据和审计保留,不执行硬删除。任务受理示例不启动 Worker;真实文件转换见[CSV→JSON场景](../examples/file-conversion.md)。 重复运行示例会新建一个独立任务并取消它,listed 数量可能增加,最多显示当前页 10 条。数据和审计保留,不执行硬删除。任务受理示例不启动 Worker;真实文件转换见[CSV→JSON场景](../examples/file-conversion.md)。
- [健康示例源码](../../sdk/go/examples/health/main.go):只读,无业务资源写入。 - [健康示例源码](../../examples/health/main.go):只读,无业务资源写入。
- [任务示例源码](../../sdk/go/examples/tasks/main.go):提交两次同一身份、获取当前状态、列表、带版本取消,再核对直接来源。 - [任务示例源码](../../examples/tasks/main.go):提交两次同一身份、获取当前状态、列表、带版本取消,再核对直接来源。
- 任务示例也接受 ORBIT_TOKEN 和 ORBIT_QUEUE_ID,环境值优先于凭据文件。 - 任务示例也接受 ORBIT_TOKEN 和 ORBIT_QUEUE_ID,环境值优先于凭据文件。
- 示例发生错误会打印错误并非零退出;打印内容不包含原始 token。 - 示例发生错误会打印错误并非零退出;打印内容不包含原始 token。
- 初始凭据 30 天有效。初始化行为和错误核对方式见 [凭据文档](../api/authentication.md)。 - 初始凭据默认长期有效,可配置固定到期时间;支持新旧 Token 过渡换证。初始化行为和错误核对方式见 [凭据文档](../api/authentication.md)。
- `make integration` 会在一次性数据库中自动完成上面的真实服务与 SDK 示例验证。 - `make integration` 会在一次性数据库中自动完成上面的真实服务与 SDK 示例验证。
## 2. 创建客户端与提交任务 ## 2. 创建客户端与提交任务
@@ -148,10 +148,10 @@ Options.HTTPClient 可注入专用 HTTP 客户端。SDK 复制配置,不修改
## 5. 外部项目通过远端接入 ## 5. 外部项目通过远端接入
业务项目需要 Go 1.27.1 或更高版本。在业务项目的 `go.mod` 所在目录安装首个接入版本: 业务项目需要 Go 1.27.1 或更高版本。在业务项目的 `go.mod` 所在目录安装当前接入版本:
```sh ```sh
go get git.yuntuo.hk/k2safe/orbit/sdk/go@v0.1.0 go get git.yuntuo.hk/k2safe/orbit/sdk/go@v0.1.2
``` ```
代码中导入: 代码中导入:
@@ -167,9 +167,9 @@ go mod tidy
go mod verify go mod verify
``` ```
SDK 位于仓库子目录,对应 Git 标签为 `sdk/go/v0.1.0`;`go get` 使用模块版本 `v0.1.0`。服务端对应仓库标签为 `v0.1.0`。业务项目固定版本并提交 `go.mod` 与 `go.sum`,无需本地源码、`replace` 或 Orbit 的 `go.work`。如果此前配置过本地替换,先执行 `go mod edit -dropreplace=git.yuntuo.hk/k2safe/orbit/sdk/go`。 SDK 位于仓库子目录,对应 Git 标签为 `sdk/go/v0.1.2`;`go get` 使用模块版本 `v0.1.2`。服务端对应仓库标签为 `v0.1.2`。业务项目固定版本并提交 `go.mod` 与 `go.sum`,无需本地源码、`replace` 或 Orbit 的 `go.work`。如果此前配置过本地替换,先执行 `go mod edit -dropreplace=git.yuntuo.hk/k2safe/orbit/sdk/go`。
这是开发与测试接入版本;生产部署仍按[交付清单](../release-checklist.md)完成目标环境验收。版本发布和校验规则见[发布说明](release.md),空缓存远端取包结果见[验证报告](../reports/phase-7-sdk-remote-release.md)。 这是开发与测试接入版本;生产部署仍按[交付清单](../release-checklist.md)完成目标环境验收。版本发布和校验规则见[发布说明](release.md),空缓存远端取包结果见[验证报告](../reports/resource-retirement.md)。
## 6. 查询执行历史与证据 ## 6. 查询执行历史与证据
@@ -193,13 +193,13 @@ for {
查询证据对应 `ListAttemptEvidence(ctx, taskID, attemptID, pageRequest)` 与 `GetAttemptEvidence(ctx, taskID, attemptID, evidenceID)`,列表相同方式使用 NextCursor。结果正文只在详情返回,列表适合按需展示。查询快照不授予执行权;证据的 outcome 是 Worker 原始声明,EVIDENCE_ONLY 不能当作任务成功。当前权威任务结果用 GetTask 核对。 查询证据对应 `ListAttemptEvidence(ctx, taskID, attemptID, pageRequest)` 与 `GetAttemptEvidence(ctx, taskID, attemptID, evidenceID)`,列表相同方式使用 NextCursor。结果正文只在详情返回,列表适合按需展示。查询快照不授予执行权;证据的 outcome 是 Worker 原始声明,EVIDENCE_ONLY 不能当作任务成功。当前权威任务结果用 GetTask 核对。
完整 [执行历史示例](../../sdk/go/examples/history/main.go) 会创建一条模拟任务,提交固定成功结果,再模拟矛盾报告,并通过上述四个查询核对历史。先按 [Worker 初始化步骤](worker.md#1-可运行的文本规范化示例) 准备具有提交、读取及 Worker 权限的专用凭据,再从仓库根目录执行: 完整 [执行历史示例](../../examples/history/main.go) 会创建一条模拟任务,提交固定成功结果,再模拟矛盾报告,并通过上述四个查询核对历史。先按 [Worker 初始化步骤](worker.md#1-可运行的文本规范化示例) 准备具有提交、读取及 Worker 权限的专用凭据,再从仓库根目录执行:
```sh ```sh
cd sdk/go cd examples
ORBIT_URL=http://127.0.0.1:8080 \ ORBIT_URL=http://127.0.0.1:8080 \
ORBIT_CREDENTIALS_FILE=../../.local/worker.credentials.json \ ORBIT_CREDENTIALS_FILE=../.local/worker.credentials.json \
go run ./examples/history go run ./history
``` ```
预期输出: 预期输出:
@@ -216,7 +216,7 @@ P2 已提供底层协议、[自动 Worker 运行器及示例](worker-runtime.md)
## 订阅管理示例 ## 订阅管理示例
[完整运行方法](../examples/subscriptions.md) 使用显式 --event-access 凭据,执行创建/同键核对/暂停/恢复/查询,再暂停本次订阅并保留审计。源码见 [examples/subscriptions](../../sdk/go/examples/subscriptions/main.go)。WSS 连接 SDK 与自动消费器见 [消费手册](event-consumer.md),可运行 [协议示例](../examples/event-protocol.md) 验证跨连接 ACK;[持久化 Inbox 示例](../examples/result-inbox.md) 已独立交付,核心SDK不新增数据库驱动。 [完整运行方法](../examples/subscriptions.md) 使用显式 --event-access 凭据,执行创建/同键核对/暂停/恢复/查询,再暂停本次订阅并保留审计。源码见 [examples/subscriptions](../../examples/subscriptions/main.go)。WSS 连接 SDK 与自动消费器见 [消费手册](event-consumer.md),可运行 [协议示例](../examples/event-protocol.md) 验证跨连接 ACK;[持久化 Inbox 示例](../examples/result-inbox.md) 已独立交付,核心SDK不新增数据库驱动。
## 流程定义发布 ## 流程定义发布

View File

@@ -1,14 +1,14 @@
# SDK 与协议兼容矩阵 # SDK 与协议兼容矩阵
当前发布线是 HTTP `/v1`、Worker WebSocket `pulse.worker.v1`、结果事件 WebSocket `orbit.events.v1`、Worker/事件帧 `protocol_version=1`、流程定义 `schema_version=1`,数据库要求 MySQL 8.4+ 与 Orbit schema v28。协议门禁由 `make protocol-check` 执行,检查服务端常量、SDK 常量、路由和机器可读 schema 是否一致。 当前发布线是 HTTP `/v1`、Worker WebSocket `pulse.worker.v1`、结果事件 WebSocket `orbit.events.v1`、Worker/事件帧 `protocol_version=1`、流程定义 `schema_version=1`,数据库要求 MySQL 8.4+ 与 Orbit schema v31。协议门禁由 `make protocol-check` 执行,检查服务端常量、SDK 常量、路由和机器可读 schema 是否一致。
| SDK / 客户端 | 服务端 | 当前证据 | 结论 | | SDK / 客户端 | 服务端 | 当前证据 | 结论 |
| --- | --- | --- | --- | | --- | --- | --- | --- |
| 当前仓库 SDK | 当前仓库服务端 | `scripts/test-protocol-compatibility.sh`、SDK 单元/竞态测试、HTTP/WSS 集成测试 | 已验证 | | 当前仓库 SDK | 当前仓库服务端 | `scripts/test-protocol-compatibility.sh`、SDK 单元/竞态测试、HTTP/WSS 集成测试 | 已验证 |
| 历史提交 `a50d5fa` SDK | 当前服务端 | `make mysql-compatibility`,真实 MySQL/HTTP 任务 API 双向演练 | 任务 API smoke 已验证;不是正式标签或全协议结论 | | 历史提交 `a50d5fa` SDK | 当前服务端 | `make mysql-compatibility`,真实 MySQL/HTTP 任务 API 双向演练 | 任务 API smoke 已验证;不是正式标签或全协议结论 |
| 当前 SDK | 历史提交 `a50d5fa` 服务端 | `make mysql-compatibility`,真实 MySQL/HTTP 任务 API 双向演练 | 任务 API smoke 已验证;不是正式标签或全协议结论 | | 当前 SDK | 历史提交 `a50d5fa` 服务端 | `make mysql-compatibility`,真实 MySQL/HTTP 任务 API 双向演练 | 任务 API smoke 已验证;不是正式标签或全协议结论 |
| 上一个正式 SDK 标签 | 当前服务端 | 仓库尚未发布正式 SDK 标签 | 未验证,不得宣称兼容 | | 上一个正式 SDK 标签 | 当前服务端 | 已发布 `sdk/go/v0.1.0`;完整跨版本协议矩阵尚未验收 | 未验证,不得宣称兼容 |
| 当前 SDK | 上一个正式服务端标签 | 仓库尚未发布正式服务端标签 | 未验证,不得宣称兼容 | | 当前 SDK | 上一个正式服务端标签 | 已发布 `v0.1.0`;完整跨版本协议矩阵尚未验收 | 未验证,不得宣称兼容 |
| 非 Go HTTP 客户端 | 当前服务端 | `/v1` 接口手册、严格输入和错误码回归 | 按接口手册逐项验证 | | 非 Go HTTP 客户端 | 当前服务端 | `/v1` 接口手册、严格输入和错误码回归 | 按接口手册逐项验证 |
## 兼容规则 ## 兼容规则

View File

@@ -5,10 +5,10 @@
业务写库与提交 Orbit 是两次独立操作。Outbox 将业务变更和待发请求放在同一个业务数据库事务中,再通过后台发送器提交任务。提交响应丢失时复用原操作身份,避免业务记录已保存而任务丢失。 业务写库与提交 Orbit 是两次独立操作。Outbox 将业务变更和待发请求放在同一个业务数据库事务中,再通过后台发送器提交任务。提交响应丢失时复用原操作身份,避免业务记录已保存而任务丢失。
```sh ```sh
go get git.yuntuo.hk/k2safe/orbit/adapters/outbox/mysql@codex/orbit-foundation go get git.yuntuo.hk/k2safe/orbit/adapters/outbox/mysql@v0.1.1
``` ```
Go 会将分支解析为固定版本写入 go.mod。上线应固定已验证的版本,不在每次部署时追踪分支。本包要求 Go 1.27.1,使用 SDK v0.1.0 和 MySQL 8.4 验证;不向核心 SDK 加入 SQL/ORM 依赖,也不依赖 Orbit 服务端模型。其他数据库和 ORM 专用适配尚未提供。 对应 Git 标签为 `adapters/outbox/mysql/v0.1.1`;业务项目固定模块版本 `v0.1.1`,无需本地 `replace`。本包要求 Go 1.27.1,使用 SDK v0.1.0 和 MySQL 8.4 验证;不向核心 SDK 加入 SQL/ORM 依赖,也不依赖 Orbit 服务端模型。其他数据库和 ORM 专用适配尚未提供。
```go ```go
import ( import (

View File

@@ -20,26 +20,30 @@ sh scripts/test-sdk-isolation.sh
成功输出示例: 成功输出示例:
```json ```json
{"sdk_module":"git.yuntuo.hk/k2safe/orbit/sdk/go","independent":true,"package_count":30,"forbidden_dependencies":0} {"sdk_module":"git.yuntuo.hk/k2safe/orbit/sdk/go","independent":true,"package_count":5,"forbidden_dependencies":0}
``` ```
`package_count` 随示例增加而变化,不能作为兼容性版本号。门禁只证明源码在当前 Go 工具链下保持独立和可构建,不代表已经发布到远端模块代理,也不替代旧 SDK/新服务端和新 SDK/旧服务端的协议兼容矩阵。 示例已移到根目录独立 module;`package_count` 随 SDK 包增加而变化,不能作为兼容性版本号。门禁只证明源码在当前 Go 工具链下保持独立和可构建,不代表已经发布到远端模块代理,也不替代旧 SDK/新服务端和新 SDK/旧服务端的协议兼容矩阵。
协议版本、WebSocket 子协议、流程 schema 和数据库版本见[兼容矩阵](compatibility.md)。发布候选还必须执行仓库根目录的 `make protocol-check`;它检查当前服务端、SDK 和机器可读 schema 是否仍在同一协议线,不把历史版本组合标记为已验证。 协议版本、WebSocket 子协议、流程 schema 和数据库版本见[兼容矩阵](compatibility.md)。发布候选还必须执行仓库根目录的 `make protocol-check`;它检查当前服务端、SDK 和机器可读 schema 是否仍在同一协议线,不把历史版本组合标记为已验证。
## 接入方式 ## 接入方式
首个接入版本为 `v0.1.0`,需要 Go 1.27.1 或更高版本。接入方应固定 SDK 版本,升级前先执行自己的接口和业务幂等回归: 当前接入版本为 `v0.1.2`,需要 Go 1.27.1 或更高版本。接入方应固定 SDK 版本,升级前先执行自己的接口和业务幂等回归:
```sh ```sh
go get git.yuntuo.hk/k2safe/orbit/sdk/go@v0.1.0 go get git.yuntuo.hk/k2safe/orbit/sdk/go@v0.1.2
# 在业务代码导入 SDK 并添加调用后: # 在业务代码导入 SDK 并添加调用后:
go mod tidy go mod tidy
go mod verify go mod verify
``` ```
仓库主分支为 `main`。服务端标签 `v0.1.0` 和独立 SDK 标签 `sdk/go/v0.1.0` 指向同一发布提交;Go 子模块标签必须包含 `sdk/go/` 前缀,业务端的模块版本不带此前缀。已发布标签保持不可变,修复使用新的补丁版本。`v0.1.0` 用于开发与测试接入,正式生产仍需完成[交付核对清单](../release-checklist.md)。 仓库主分支为 `main`。服务端标签 `v0.1.2` 和独立 SDK 标签 `sdk/go/v0.1.2` 指向同一发布提交;Go 子模块标签必须包含 `sdk/go/` 前缀,业务端的模块版本不带此前缀。已发布标签保持不可变,修复使用新的补丁版本。版本发布不替代目标环境验收,正式生产仍需完成[交付核对清单](../release-checklist.md)。
`v0.1.0` 已在仓库外的新业务 module、空模块缓存和 `GOWORK=off` 下通过公开远端下载、`go mod tidy`、编译、SDK HTTP smoke 和 `go mod verify`,解析版本精确为 `v0.1.0` 且不存在 `Replace`。发布提交、校验和与网络条件见[远端验证报告](../reports/phase-7-sdk-remote-release.md)。后续发布继续重复这一步,并按[兼容矩阵](compatibility.md)验证旧/新组合。 `v0.1.0` 已在仓库外的新业务 module、空模块缓存和 `GOWORK=off` 下通过公开远端下载、`go mod tidy`、编译、SDK HTTP smoke 和 `go mod verify`,解析版本精确为 `v0.1.0` 且不存在 `Replace`。发布提交、校验和与网络条件见[远端验证报告](../reports/phase-7-sdk-remote-release.md)。后续发布继续重复这一步,并按[兼容矩阵](compatibility.md)验证旧/新组合。
本地联调可以临时添加 `replace`,但不能提交到业务项目的发布分支。SDK 不负责 TLS 终止、凭据托管、对象存储或外部副作用核查;这些边界仍由平台接口手册和接入方运行手册定义。 本地联调可以临时添加 `replace`,但不能提交到业务项目的发布分支。SDK 不负责 TLS 终止、凭据托管、对象存储或外部副作用核查;这些边界仍由平台接口手册和接入方运行手册定义。
Outbox 独立模块使用 `adapters/outbox/mysql/v0.1.1` 标签,安装与版本边界见[适配包手册](outbox-mysql.md)。本次目录整理、发布与远端取包验证见[v0.1.1 记录](../reports/v0.1.1-release.md)。
`v0.1.2` 发布队列/订阅退役与对应 SDK 方法,数据库升级到 000034;[本次报告](../reports/resource-retirement.md)列出隔离回归与远端安装结果。Outbox 不需要同步升级。

View File

@@ -2,17 +2,17 @@
更新:2026-09-17。自动 Worker 已实现,并通过真实 MySQL、实际服务命令、WSS 断线/ACK 丢失/持续断网及 [进程强杀恢复回归](../reports/phase-2.md)。[尝试与证据查询](../api/execution-history.md) 可核对结果,协议形状见 [Schema](../api/worker-schema.md)。 更新:2026-09-17。自动 Worker 已实现,并通过真实 MySQL、实际服务命令、WSS 断线/ACK 丢失/持续断网及 [进程强杀恢复回归](../reports/phase-2.md)。[尝试与证据查询](../api/execution-history.md) 可核对结果,协议形状见 [Schema](../api/worker-schema.md)。
源码:[运行器](../../sdk/go/worker_runtime.go)、[配置与中文注释](../../sdk/go/worker_runtime_types.go)、[完整示例](../../sdk/go/examples/worker/main.go)。特殊传输集成可以使用 [底层协议 SDK](worker.md),普通消费直接使用本页的 Worker。 源码:[运行器](../../sdk/go/worker_runtime.go)、[配置与中文注释](../../sdk/go/worker_runtime_types.go)、[完整示例](../../examples/worker/main.go)。特殊传输集成可以使用 [底层协议 SDK](worker.md),普通消费直接使用本页的 Worker。
## 1. 运行完整示例 ## 1. 运行完整示例
按 [底层 SDK 的初始化步骤](worker.md#1-可运行的文本规范化示例) 创建具有 Worker 权限的专用凭据,在仓库根目录执行: 按 [底层 SDK 的初始化步骤](worker.md#1-可运行的文本规范化示例) 创建具有 Worker 权限的专用凭据,在仓库根目录执行:
```sh ```sh
cd sdk/go cd examples
ORBIT_URL=http://127.0.0.1:8080 \ ORBIT_URL=http://127.0.0.1:8080 \
ORBIT_CREDENTIALS_FILE=../../.local/worker.credentials.json \ ORBIT_CREDENTIALS_FILE=../.local/worker.credentials.json \
go run ./examples/worker go run ./worker
``` ```
示例提交三条文本任务,以容量 2 启动自动 Worker,真实执行文本规范化,查询结果后取消 Run context 并等待排空。预期输出: 示例提交三条文本任务,以容量 2 启动自动 Worker,真实执行文本规范化,查询结果后取消 Run context 并等待排空。预期输出:

View File

@@ -14,10 +14,10 @@ chmod 700 .local
go run ./cmd/orbit-admin bootstrap \ go run ./cmd/orbit-admin bootstrap \
--application worker-example --namespace default --environment development \ --application worker-example --namespace default --environment development \
--queue normalization --worker-access --output .local/worker.credentials.json --queue normalization --worker-access --output .local/worker.credentials.json
cd sdk/go cd examples
ORBIT_URL=http://127.0.0.1:8080 \ ORBIT_URL=http://127.0.0.1:8080 \
ORBIT_CREDENTIALS_FILE=../../.local/worker.credentials.json \ ORBIT_CREDENTIALS_FILE=../.local/worker.credentials.json \
go run ./examples/worker-protocol go run ./worker-protocol
``` ```
预期输出: 预期输出:
@@ -26,7 +26,7 @@ ORBIT_URL=http://127.0.0.1:8080 \
task=<32位任务ID> final_state=SUCCEEDED attempts=1 result={"text":"HELLO ORBIT"} task=<32位任务ID> final_state=SUCCEEDED attempts=1 result={"text":"HELLO ORBIT"}
``` ```
[完整源码](../../sdk/go/examples/worker-protocol/main.go) 实际提交 `{"text":" Hello Orbit "}`,领取并取得开始授权,执行去首尾空格/转大写,报告结果、查询当前状态并排空。没有生成文件或调用外部服务。每次运行创建独立任务与临时处理器名,避免消费前次示例遗留任务;历史和审计保留,不硬删除。 [完整源码](../../examples/worker-protocol/main.go) 实际提交 `{"text":" Hello Orbit "}`,领取并取得开始授权,执行去首尾空格/转大写,报告结果、查询当前状态并排空。没有生成文件或调用外部服务。每次运行创建独立任务与临时处理器名,避免消费前次示例遗留任务;历史和审计保留,不硬删除。
安全重试可通过 `WorkerFinish.Retryable=true` 声明明确失败允许再试,仅适用于 WorkerFailed;省略为 false。新尝试由服务端决定,详见 [安全重试](../api/retries.md)。 安全重试可通过 `WorkerFinish.Retryable=true` 声明明确失败允许再试,仅适用于 WorkerFailed;省略为 false。新尝试由服务端决定,详见 [安全重试](../api/retries.md)。

110
examples/README.md Normal file
View File

@@ -0,0 +1,110 @@
# Orbit 可运行示例
这里集中提供 28 个场景:25 个轻量 SDK 程序和 3 个包含业务数据库的完整工程。每个目录的 README 都有用途、前置条件、运行命令、预期结果及详细接口链接。
## 第一次使用
1. 按[根 README](../README.md#快速开始)迁移数据库、设置管理员并启动 Orbit。
2. 从 `health` 检查服务,再运行 `worker` 看完整提交与执行结果。
3. 接入已有业务优先阅读 `http-service`;只需要事务发送器,使用公共 [Outbox 适配包](../adapters/outbox/mysql/README.md)。
轻量示例在根 `examples/go.mod` 中,仓库 `go.work` 联调本地 SDK;`GOWORK=off` 时使用已发布的最低兼容版本 v0.1.0。v0.1.1 的这些 SDK API 保持不变。三个业务工程各有独立 go.mod,用 `GOWORK=off` 运行;它们保留仓库内开发用的 replace。**业务方自己的项目安装正式 v0.1.1,无需复制这些 replace。**
从仓库根目录执行:
```sh
export ORBIT_URL=http://127.0.0.1:8080
export ORBIT_CREDENTIALS_FILE="$PWD/.local/development.credentials.json"
cd examples
go run ./health
go run ./worker
```
SDK 凭据是程序调用接口的身份,不是业务数据。任务、流程、结果与审计在 MySQL;控制台使用账号密码登录,无需上传凭据文件。
## 全部示例
| 目录 | 功能 | 本例实际演示 |
| --- | --- | --- |
| [health](health/README.md) | 健康检查 | 查询存活、数据库/迁移就绪状态与运行版本。 |
| [tasks](tasks/README.md) | 任务提交与幂等 | 同一请求提交两次,查询任务和直接来源,再按版本取消。 |
| [worker](worker/README.md) | 自动 Worker | 注册文本处理器,执行三条任务,确认结果后有界排空。 |
| [file-conversion](file-conversion/README.md) | CSV 转 JSON | 提交小型 CSV 内容,Worker 转为 JSON,并核对行数和输出。 |
| [delayed-task](delayed-task/README.md) | 延迟任务 | 等待 1500 毫秒后执行,核对未提前开始及原受理回执。 |
| [batch](batch/README.md) | 批量与部分补交 | 三项受理中两项成功、一项满额;原身份核对并只补交失败项。 |
| [retry](retry/README.md) | 有限安全重试 | 第一次明确失败且未产生效果,退避后第二次成功。 |
| [cancellation](cancellation/README.md) | 运行中取消 | 处理器收到取消意图后配合停止,确认没有未结清效果。 |
| [task-query](task-query/README.md) | 任务筛选与分页 | 按精确业务键和创建时间翻页,核对时间上界与原载荷,再取消收尾。 |
| [history](history/README.md) | 执行历史与迟到证据 | 保存成功结果后提交冲突报告,查询尝试及证据,确认原结果没有被覆盖。 |
| [recovery](recovery/README.md) | 人工核查与关联重试 | 模拟未知效果,凭证据核查为失败,再创建关联的新任务并成功执行。 |
| [schedules](schedules/README.md) | 定时计划 | 创建有限周期计划,恢复运行,读取固定版本触发来源,最后暂停并排空。 |
| [resources](resources/README.md) | 队列配额与限速 | 制造队列积压背压,释放额度后以原身份补交,并验证受控执行。 |
| [application-resources](application-resources/README.md) | 跨命名空间共享额度 | 同一应用下两个命名空间共享上限,释放后原身份重报,并恢复配置。 |
| [keyed-concurrency](keyed-concurrency/README.md) | 跨队列资源互斥 | 两队列操作同一资源键,验证许可序号递增及资源端拒绝旧写。 |
| [priority](priority/README.md) | 优先级 | 以单执行槽展示近同时到期的任务按 9、4、0 优先级执行。 |
| [subscriptions](subscriptions/README.md) | 结果订阅管理 | 创建订阅、同键核对、暂停、恢复及查询,最后暂停本次订阅。 |
| [event-protocol](event-protocol/README.md) | WebSocket 结果通知与 ACK | 接收取消事件并确认,断开后重报原证明,验证 ACK 去重。 |
| [worker-protocol](worker-protocol/README.md) | Worker 底层协议 | 手动完成注册、领取、开始授权、结果确认和查询,了解协议边界。 |
| [workflow-definition](workflow-definition/README.md) | 流程定义与版本发布 | 研发通过 SDK 定义并发布 v1/v2,核对原版本与结构预算。 |
| [workflow](workflow/README.md) | 并行流程、汇合与信号 | 两条并行任务汇合,等待信号后推进,并查询来源和状态时间线。 |
| [workflow-query](workflow-query/README.md) | 流程实例筛选与分页 | 创建带业务键的实例,按业务键/状态/时间分页并核对尾部空格精确匹配。 |
| [workflow-poll](workflow-poll/README.md) | 有界查询 | 提交外部作业一次,区分处理中轮次与请求失败重试,并演示轮次耗尽。 |
| [workflow-recovery](workflow-recovery/README.md) | 流程证据核查与恢复 | 外部受理后丢响应,按证据核查、解决步骤、解除核查并显式恢复暂停。 |
| [task-outbox](task-outbox/README.md) | 业务事务 Outbox | 业务记录与待发请求同事务,后台提交及原身份恢复 |
| [result-inbox](result-inbox/README.md) | 业务结果 Inbox | 同事务去重和更新业务视图,提交后 ACK |
| [http-service](http-service/README.md) | 嵌入 HTTP 服务 | HTTP → Outbox → Worker → 结果 Inbox,完整启动、就绪和关闭 |
## 权限与准备
根 README 的快速开始凭据用于专用演示环境,包含 Worker、计划、订阅、任务恢复和全部流程权限。若单独初始化,按各例要求选择:
| 能力 | bootstrap 参数 |
| --- | --- |
| Worker 执行 | `--worker-access` |
| 定时计划 | `--schedule-access` |
| 结果订阅 | `--event-access` |
| 独立任务核查/重试 | `--recovery-access` |
| 定义发布 | `--workflow-access` |
| 实例启动/读取 | `--workflow-run-access` |
| 暂停/恢复/取消 | `--workflow-control-access` |
| 外部信号 | `--workflow-signal-access` |
| 步骤核查/恢复 | `--workflow-recovery-access` |
| 流程审计/时间线 | `--workflow-audit-access` |
| 应用共享额度 | `--resource-access`,见 application-resources 的双命名空间初始化 |
已有凭据不会因修改命令自动增加权限。不要重复 bootstrap 覆盖原凭据;需要另一个场景时按对应手册创建独立示例应用并保存新文件。生产凭据按实际角色和队列收紧权限。
需要完整流程演示凭据时,在已配置 `ORBIT_MYSQL_DSN` 的仓库根目录执行一次:
```sh
umask 077
mkdir -p .local
go run ./cmd/orbit-admin bootstrap \
--application workflow-examples --namespace default --environment development \
--queue workflow --worker-access --workflow-access --workflow-run-access \
--workflow-control-access --workflow-signal-access --workflow-recovery-access \
--workflow-audit-access --output .local/workflow.credentials.json
export ORBIT_CREDENTIALS_FILE="$PWD/.local/workflow.credentials.json"
cd examples
go run ./workflow
go run ./workflow-poll
go run ./workflow-recovery
```
三个业务数据库工程的 `init` 仅用于新建专用空库;连接配置、命令参数与 API 请求分别在各自 README 链接的运行手册中。其数据库不能用 Orbit 平台库替代。
## 执行与恢复约定
- `ACCEPTED` 是任务已被平台受理;执行成功以查询或结果事件为准。
- 短示例通常随机创建身份用于独立演示;重启短示例不是恢复旧业务,持久恢复参考 Outbox/Inbox 工程。
- `PENDING` 查询结果表示继续等待,网络失败重试属于另一层预算。
- 示例使用真实接口并保留审计,不清空平台数据库。订阅、定义和队列会累计,应在专用环境演练。
- 外部系统有未知效果时应核查;处理器自己的幂等、事务和证据不能由重连机制替代。
## 回归
从仓库根目录执行 `make test vet build` 覆盖全部示例模块;`make integration` 使用临时 MySQL 和真实 Orbit 进程运行场景与故障测试。仅跑 `go test ./...` 而未提供集成环境时,外部服务用例会跳过。
## 通用资源退役
[resource-lifecycle](../sdk/go/examples/resource-lifecycle/README.md) 位于 SDK module,可用当前 SDK 源码直接运行;只创建和退役本次独占的空队列及订阅,验证幂等与历史保留。

View File

@@ -0,0 +1,31 @@
# 跨命名空间共享额度
同一应用下两个命名空间共享上限,释放后原身份重报,并恢复配置。
## 准备
- Go 1.27.1、当前版本 Orbit;服务启动和初始化见[仓库 README](../../README.md#快速开始)。
- 须按详细手册创建同一专用应用下的两个命名空间,两个凭据均增加 --resource-access。不能直接使用单份快速开始凭据。
- [示例总索引](../README.md)提供统一初始化和权限说明;完整字段、失败处理见[详细手册](../../docs/api/application-resources.md)。
## 运行
以下命令从仓库根目录执行;凭据路径替换为实际初始化输出。
```sh
cd examples
export ORBIT_URL=http://127.0.0.1:8080
export ORBIT_CREDENTIALS_FILE="$PWD/../.local/app-first.credentials.json"
export ORBIT_SECOND_CREDENTIALS_FILE="$PWD/../.local/app-second.credentials.json"
go run ./application-resources
```
## 结果核对
cross_namespace_backpressure=APPLICATION_FULL http=429;same_identity_retry_accepted=true;unfinished=0。具体 ID 和统计值以本次运行为准。程序会核对上述关键条件,失败时打印错误并以非零状态退出。
## 接入自己的项目
阅读[main.go](main.go)中的客户端创建、请求及错误处理。业务项目通过 `go get git.yuntuo.hk/k2safe/orbit/sdk/go@v0.1.1` 引入 SDK,无需导入本示例包。
示例运行会写入真实平台数据,应使用专用测试应用/队列。正常结束保留历史和审计;重复演示通常创建新身份,不能当作上次失败操作的恢复。真实业务应在第一次请求前持久化操作身份,网络结果不明时沿原身份核对。

30
examples/batch/README.md Normal file
View File

@@ -0,0 +1,30 @@
# 批量与部分补交
三项受理中两项成功、一项满额;原身份核对并只补交失败项。
## 准备
- Go 1.27.1、当前版本 Orbit;服务启动和初始化见[仓库 README](../../README.md#快速开始)。
- 队列创建/配置和任务权限;使用允许创建新队列的示例凭据,不需要 Worker。
- [示例总索引](../README.md)提供统一初始化和权限说明;完整字段、失败处理见[详细手册](../../docs/examples/batch.md)。
## 运行
以下命令从仓库根目录执行;凭据路径替换为实际初始化输出。
```sh
cd examples
export ORBIT_URL=http://127.0.0.1:8080
export ORBIT_CREDENTIALS_FILE="$PWD/../.local/development.credentials.json"
go run ./batch
```
## 结果核对
accepted=2 rejected=1;replayed=2;retried_items=1;unfinished=0。具体 ID 和统计值以本次运行为准。程序会核对上述关键条件,失败时打印错误并以非零状态退出。
## 接入自己的项目
阅读[main.go](main.go)中的客户端创建、请求及错误处理。业务项目通过 `go get git.yuntuo.hk/k2safe/orbit/sdk/go@v0.1.1` 引入 SDK,无需导入本示例包。
示例运行会写入真实平台数据,应使用专用测试应用/队列。正常结束保留历史和审计;重复演示通常创建新身份,不能当作上次失败操作的恢复。真实业务应在第一次请求前持久化操作身份,网络结果不明时沿原身份核对。

View File

@@ -0,0 +1,30 @@
# 运行中取消
处理器收到取消意图后配合停止,确认没有未结清效果。
## 准备
- Go 1.27.1、当前版本 Orbit;服务启动和初始化见[仓库 README](../../README.md#快速开始)。
- 初始化时增加 --worker-access;还需任务取消权限。
- [示例总索引](../README.md)提供统一初始化和权限说明;完整字段、失败处理见[详细手册](../../docs/api/cancellation.md)。
## 运行
以下命令从仓库根目录执行;凭据路径替换为实际初始化输出。
```sh
cd examples
export ORBIT_URL=http://127.0.0.1:8080
export ORBIT_CREDENTIALS_FILE="$PWD/../.local/development.credentials.json"
go run ./cancellation
```
## 结果核对
accepted_state=RUNNING;final_state=CANCELLED;worker_drained=true。具体 ID 和统计值以本次运行为准。程序会核对上述关键条件,失败时打印错误并以非零状态退出。
## 接入自己的项目
阅读[main.go](main.go)中的客户端创建、请求及错误处理。业务项目通过 `go get git.yuntuo.hk/k2safe/orbit/sdk/go@v0.1.1` 引入 SDK,无需导入本示例包。
示例运行会写入真实平台数据,应使用专用测试应用/队列。正常结束保留历史和审计;重复演示通常创建新身份,不能当作上次失败操作的恢复。真实业务应在第一次请求前持久化操作身份,网络结果不明时沿原身份核对。

View File

@@ -0,0 +1,30 @@
# 延迟任务
等待 1500 毫秒后执行,核对未提前开始及原受理回执。
## 准备
- Go 1.27.1、当前版本 Orbit;服务启动和初始化见[仓库 README](../../README.md#快速开始)。
- 初始化时增加 --worker-access。
- [示例总索引](../README.md)提供统一初始化和权限说明;完整字段、失败处理见[详细手册](../../docs/examples/delayed-task.md)。
## 运行
以下命令从仓库根目录执行;凭据路径替换为实际初始化输出。
```sh
cd examples
export ORBIT_URL=http://127.0.0.1:8080
export ORBIT_CREDENTIALS_FILE="$PWD/../.local/development.credentials.json"
go run ./delayed-task
```
## 结果核对
no_early_start=true original_receipt=true worker_drained=true。具体 ID 和统计值以本次运行为准。程序会核对上述关键条件,失败时打印错误并以非零状态退出。
## 接入自己的项目
阅读[main.go](main.go)中的客户端创建、请求及错误处理。业务项目通过 `go get git.yuntuo.hk/k2safe/orbit/sdk/go@v0.1.1` 引入 SDK,无需导入本示例包。
示例运行会写入真实平台数据,应使用专用测试应用/队列。正常结束保留历史和审计;重复演示通常创建新身份,不能当作上次失败操作的恢复。真实业务应在第一次请求前持久化操作身份,网络结果不明时沿原身份核对。

View File

@@ -0,0 +1,32 @@
# WebSocket 结果通知与 ACK
接收取消事件并确认,断开后重报原证明,验证 ACK 去重。
## 准备
- Go 1.27.1、当前版本 Orbit;服务启动和初始化见[仓库 README](../../README.md#快速开始)。
- 初始化时增加 --event-access;用隔离队列运行,避免混入其他取消事件。
- [示例总索引](../README.md)提供统一初始化和权限说明;完整字段、失败处理见[详细手册](../../docs/examples/event-protocol.md)。
## 运行
以下命令从仓库根目录执行;凭据路径替换为实际初始化输出。
```sh
cd examples
export ORBIT_URL=http://127.0.0.1:8080
export ORBIT_CREDENTIALS_FILE="$PWD/../.local/development.credentials.json"
go run ./event-protocol
```
## 结果核对
ack_replayed=true same_receipt=true pending=0 subscription_enabled=false。具体 ID 和统计值以本次运行为准。程序会核对上述关键条件,失败时打印错误并以非零状态退出。
## 接入自己的项目
阅读[main.go](main.go)中的客户端创建、请求及错误处理。业务项目通过 `go get git.yuntuo.hk/k2safe/orbit/sdk/go@v0.1.1` 引入 SDK,无需导入本示例包。
示例运行会写入真实平台数据,应使用专用测试应用/队列。正常结束保留历史和审计;重复演示通常创建新身份,不能当作上次失败操作的恢复。真实业务应在第一次请求前持久化操作身份,网络结果不明时沿原身份核对。
每次演示保留一个暂停订阅,命名空间最多 64 个订阅;不要将重复运行示例作为持续消费者。

View File

@@ -0,0 +1,30 @@
# CSV 转 JSON
提交小型 CSV 内容,Worker 转为 JSON,并核对行数和输出。
## 准备
- Go 1.27.1、当前版本 Orbit;服务启动和初始化见[仓库 README](../../README.md#快速开始)。
- 初始化时增加 --worker-access;输入内置,不需要外部文件存储。
- [示例总索引](../README.md)提供统一初始化和权限说明;完整字段、失败处理见[详细手册](../../docs/examples/file-conversion.md)。
## 运行
以下命令从仓库根目录执行;凭据路径替换为实际初始化输出。
```sh
cd examples
export ORBIT_URL=http://127.0.0.1:8080
export ORBIT_CREDENTIALS_FILE="$PWD/../.local/development.credentials.json"
go run ./file-conversion
```
## 结果核对
rows=2 state=SUCCEEDED worker_drained=true。具体 ID 和统计值以本次运行为准。程序会核对上述关键条件,失败时打印错误并以非零状态退出。
## 接入自己的项目
阅读[main.go](main.go)中的客户端创建、请求及错误处理。业务项目通过 `go get git.yuntuo.hk/k2safe/orbit/sdk/go@v0.1.1` 引入 SDK,无需导入本示例包。
示例运行会写入真实平台数据,应使用专用测试应用/队列。正常结束保留历史和审计;重复演示通常创建新身份,不能当作上次失败操作的恢复。真实业务应在第一次请求前持久化操作身份,网络结果不明时沿原身份核对。

Some files were not shown because too many files have changed in this diff Show More