Files
orbit/README.md

285 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Orbit · 星轨
**Go + MySQL 构建的任务调度与流程编排平台。** 业务应用通过 HTTP 提交任务,Worker 通过 WebSocket 执行,结果通过可靠订阅交付;任务状态、计划、流程检查点与审计保存在 MySQL。
- **Pulse · 脉动**:异步任务、延迟执行、定时计划、执行授权、重试与结果订阅。
- **Weave · 织流**:研发定义并发布流程,支持顺序、并行、条件分支、等待信号、有界查询和人工恢复。
- **Console**:账号密码登录的管理工作台,按应用与环境查看运行快照;支持任务/流程筛选、资源分页、ID 定位、审计与接入配置复制。[控制台使用说明](docs/console.md)。
主分支:`main`。当前版本:**`v0.1.2`**。源码、SDK 和 Outbox 适配包采用固定版本发布,已发布标签不覆盖。变更见 [CHANGELOG](CHANGELOG.md)。
## 从这里开始
| 你要做什么 | 入口 |
| --- | --- |
| 第一次启动平台、设置管理员 | [快速开始](#快速开始) |
| 使用 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) |
## 功能一览
每个示例目录都有 README、源码、启动方式和结果核对。接口手册包含字段、权限、错误码和恢复约定。
### Pulse:任务与调度
| 功能 | 做什么 / 怎么用 | 可运行示例 / 接口 |
| --- | --- | --- |
| 即时任务与提交幂等 | `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) |
### 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
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_HTTP_ADDR='127.0.0.1:8080'
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
```
打开 **<http://127.0.0.1:8080/console/>**,用 `admin` 和刚设置的密码登录。页面自动使用当前访问地址请求服务端,统计与列表从平台接口读取 MySQL 中的数据。
### 4. 跑一条完整执行链
另开终端,从仓库根目录执行:
```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
```
健康检查显示 `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
go get git.yuntuo.hk/k2safe/orbit/sdk/go@v0.1.2
# 业务事务需要 MySQL Outbox 时再安装:
go get git.yuntuo.hk/k2safe/orbit/adapters/outbox/mysql@v0.1.1
```
无需本地源码或 `replace`。SDK 是独立 Go module,只依赖标准库和 WebSocket 客户端;MySQL 驱动属于可选适配包。子模块的 Git 标签分别为 `sdk/go/v0.1.2` 和 `adapters/outbox/mysql/v0.1.1`。
### 提交、执行、接收结果
一次完整接入分为三个角色,可以分进程,也可以嵌入同一业务 HTTP 服务:
```text
业务事务 → Outbox → HTTP 提交到 Orbit → WebSocket Worker 执行业务
↓
业务数据 ← Inbox ← WebSocket 结果订阅 ← 持久化结果
```
下面是业务函数中的提交片段;完整 imports、main、Worker 注册和收尾见 [worker/main.go](examples/worker/main.go)。`baseURL` 为实际平台地址,例如 `https://orbit.example.com`;`token` 和 `queueID` 从业务配置/Secret 注入。
```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 时,提交成功也不会立即执行。
**任务受理不等于执行成功。** 同键重报返回原回执,最新状态用 `GetTask` 或结果事件核对。平台不能替外部系统保证“恰好执行一次”;副作用须使用业务幂等键、事务或证据核查。
结果通知使用 `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
curl --fail http://127.0.0.1:8080/health/ready
go run ./cmd/orbit-admin verify
go run ./cmd/orbit-admin observe snapshot
```
数据库禁止外键和级联删除;关联一致性由事务校验,保留唯一约束、索引和 CHECK。持久化模型及 SQL 字段都有中文注释。已有迁移不可回改,演进采用前向迁移。
## 项目目录
```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、场景、设计及验收报告
```
## 测试、版本与边界
在仓库根目录执行:
```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)。