docs: define idempotent Client registration contract (#12)
This commit is contained in:
@@ -12,7 +12,8 @@
|
||||
|
||||
**核心:Admin 是调度器,Client 是执行器,执行器不参与调度决策。**
|
||||
|
||||
- Client 只有三个动作:领一个任务、提交结果、提交失败。**没有任何"去问 Admin 现在怎么想"的调用。**
|
||||
- Client 的任务流程只有三个动作:领一个任务、提交结果、提交失败。
|
||||
设置页另有一个幂等 Client 登记动作。**没有任何"去问 Admin 现在怎么想"的调用。**
|
||||
- Client 拿到任务就做完,中途不管任务是否被取消、是否被重派。
|
||||
- Admin 负责任务的创建、更新、取消和派发(含重派),这些 Client 一律不感知。
|
||||
- 结果提交必须幂等;网络重试不能创建重复结果。
|
||||
@@ -109,6 +110,59 @@ Idempotency-Key: <stable-key>
|
||||
|
||||
任务对象里**不含 Admin 侧状态**。Client 不关心 Admin 那边把它标成什么,只管做完提交。
|
||||
|
||||
## 4.1 登记或更新 Client
|
||||
|
||||
```http
|
||||
PUT /api/v1/client/registration
|
||||
X-Client-Id: <stable-client-id>
|
||||
X-Request-Id: <uuid>
|
||||
```
|
||||
|
||||
请求:
|
||||
|
||||
```json
|
||||
{
|
||||
"client": {
|
||||
"name": "办公室-01"
|
||||
},
|
||||
"supported_types": ["collect", "purchase"],
|
||||
"device": {
|
||||
"address": "192.168.0.173:5555",
|
||||
"platform": "android",
|
||||
"pdd_package": "com.xunmeng.pinduoduo"
|
||||
},
|
||||
"capabilities": {
|
||||
"purchase_mode": "dry_run",
|
||||
"schema_versions": [1]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
成功统一返回 `200 OK`:
|
||||
|
||||
```json
|
||||
{
|
||||
"registered": true,
|
||||
"client_id": "CLIENT-123456",
|
||||
"registered_at": "2026-08-06T09:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
规则:
|
||||
|
||||
- `[必须]` `X-Client-Id` 是 Client 唯一键;相同编号重复 `PUT` 执行幂等 upsert,不创建重复记录。
|
||||
- `[必须]` 登记接口不读取、领取或修改任务,也不返回任务。
|
||||
- `[必须]` `client.name` 可选且最多 50 字。显式登记携带非空名称时允许更新 Admin 名称;空名称更新保留已有名称,新建时用 Client ID 兜底。
|
||||
- `[必须]` 更新设备、能力、`last_seen_at` 和 `updated_at`。
|
||||
- `[必须]` `supported_types` 非空且只包含 `collect`、`purchase`;`purchase_mode` 只允许 `dry_run`、`live`;`schema_versions` 只包含正整数。
|
||||
- `[必须]` Client 必须先把设备号和名称保存到 SQLite,再在后台线程调用本接口;远端失败不得回滚本地保存。
|
||||
- `[必须]` 设备号生成后稳定复用,不向 Admin 发送生成设备号所用的原始硬件参数。
|
||||
- `[必须]` 不增加定时心跳。在线状态仍由登记、领取和提交产生的 `last_seen_at` 派生。
|
||||
|
||||
错误至少包括 `MISSING_CLIENT_ID`、`INVALID_BODY`、`INVALID_CLIENT_PROFILE` 和 `CLIENT_REGISTER_FAILED`,并使用 §3 的统一结构。
|
||||
|
||||
`claim` 继续支持隐式登记作为旧 Client 的兼容兜底:新编号可以创建 Client,已有 Client 只更新设备、能力和最近活动时间,不覆盖名称。
|
||||
|
||||
## 5. 领取任务
|
||||
|
||||
```http
|
||||
@@ -145,12 +199,11 @@ POST /api/v1/client/tasks/claim
|
||||
|
||||
无可领取任务时返回 `204 No Content`。
|
||||
|
||||
`[必须]` **`204` 不是错误。** 新客户端第一次调 `claim` 必然是 204——
|
||||
它刚被登记,还没有人给它分配任务。Client 要把它当"暂时没活干"处理,
|
||||
不要报错,也不要因此触发重试风暴。
|
||||
`[必须]` **`204` 不是错误。** Client 要把它当"暂时没活干"处理,
|
||||
不要报错,也不要因此触发重试风暴。首次 claim 通常返回 204;如果该编号已经预先分配任务,也可以直接返回 200。
|
||||
|
||||
`client.name` 是给人看的显示名,可以不填(不填时 Admin 用 `X-Client-Id` 兜底)。
|
||||
它**只在首次登记时被采纳**,之后操作员在 Admin 改的名字不会被客户端覆盖。
|
||||
`client.name` 是给人看的显示名,可以不填(新建时 Admin 用 `X-Client-Id` 兜底)。
|
||||
在 claim 兼容登记中,它只在首次创建时被采纳,已有 Client 的名称不会被后台领取覆盖;用户通过 §4.1 显式保存非空名称时可以更新。
|
||||
|
||||
> 怎么把这条链路跑通、怎么确认设备登记成功,见
|
||||
> [Admin 侧的设备登记联调手册](../admin/07-设备登记联调手册.md)。
|
||||
@@ -266,9 +319,10 @@ Idempotency-Key: task-id:attempt-id:failure-v1
|
||||
|
||||
## 9. Mock Admin 要求
|
||||
|
||||
`MockAdminGateway` 与 HTTP 实现暴露同一应用层接口,只有三个方法:
|
||||
`MockAdminGateway` 与 HTTP 实现暴露同一应用层接口。登记和三个任务方法都必须使用同一契约:
|
||||
|
||||
```text
|
||||
register_client(client, capabilities) # §4.1
|
||||
claim_next(client, capabilities) # §5
|
||||
submit_result(task_id, idempotency_key, result) # §6
|
||||
submit_failure(task_id, idempotency_key, failure) # §7
|
||||
@@ -300,7 +354,7 @@ Admin 还没做完,下面这些要和 Admin 一起定。**不许因此停工**
|
||||
**已定案(不再是待确认项):**
|
||||
|
||||
- Admin 只把任务分配给指定 Client,Client 不读全局任务池。见 §5.1。
|
||||
- **没有租约、没有心跳、没有状态回查。** Client 只有 §5 / §6 / §7 三个调用。见 §1.1。
|
||||
- **没有租约、没有心跳、没有状态回查。** 任务流程只有 §5 / §6 / §7 三个调用;设置页另有 §4.1 的幂等登记调用。
|
||||
- Admin 必须无条件接受已派发过的 Client 提交的结果。见 §6.1。
|
||||
|
||||
改动这张表里任何一条,都属于会影响业务结果的变更,必须先更新工单并经用户确认。
|
||||
|
||||
Reference in New Issue
Block a user