modify: json 解析优化

This commit is contained in:
2026-08-22 03:53:31 +08:00
parent 440efa716f
commit 8b13ed17e6
9 changed files with 603 additions and 44 deletions
+2 -2
View File
@@ -15,7 +15,7 @@
| - | ---- | ---- |
| P1 | **规范先行,协议是唯一契约** | 网关与插件之间只认线协议([plugin-wire-protocol.md](./plugin-wire-protocol.md))。任何语言实现均以规范为准,不得依赖其他语言 SDK 的内部行为 |
| P2 | **网关零改动起步** | 阶段 1 的 Rust 插件按协议实现即可对接,网关代码不允许为适配单语言做改动 |
| P3 | **混合部署兼容** | 同一 `<type>` 下可混布 Python 与 Rust 副本(协议相同、负载均衡透明);但流式语义、错误格式、超时行为必须与规范完全一致 |
| P3 | **混合部署兼容** | 同一 `<type>` 下可混布 Python 与 Rust 副本(协议相同、负载均衡透明);但流式语义、错误格式(非流式经 `reply_err` 通道)、超时行为必须与规范完全一致 |
| P4 | **契约校验不旁路** | Python SDK 的进程内契约校验(TOML ↔ 注册 ↔ 模型)是 Python 特有能力;其他语言实现须提供等价的自检(描述符字段完整性),网关侧强校验在阶段 2 补齐 |
| P5 | **修改即更新规范** | 任何实现侧改动触及协议语义时,必须同步修订规范(含[附录 A 事实来源索引](./plugin-wire-protocol.md)) |
| P6 | **性能收益只认实测** | 语言选型以基准测试为准(见 §6),不凭直觉切换 |
@@ -75,7 +75,7 @@ chongming-worker-rs/ # 独立仓库(或 utils/worker-rs/,与 Pyth
| §2 路由描述符 | `descriptor.rs` 构造 + `publisher.rs` PUT/DELETE;`route_id = subject.replace('.','_') + "__" + METHOD` |
| §3 服务发现 | `session.liveliness().declare_token("worker/<type>/<id>")`,`--count` 多副本 id 互异 |
| §4 RPC | `declare_queryable("worker/<type>/<id>/<subject>")` 异步 handler;信封解析 + 分派;流式多次 `query.reply()` |
| §4.3 异常 | 非流式:`{"result":0.0,"operation":"error","error":...,"worker":...}`;流式:`{"error":...}` 收尾块 |
| §4.3 异常 | 非流式:`query.reply_err(...)`,载荷 `{"result":0.0,"operation":"error","error":...,"worker":...}`;流式:`{"error":...}` 收尾块(普通 reply) |
| §5 配置 | `config.rs`:TOML + JSON5 双重解析 |
| 生命周期 | `publisher.rs` 10s tokio interval 重发布;`tokio::signal` 监听 SIGTERM/SIGINT → DELETE 全部 key |
+27 -3
View File
@@ -81,6 +81,7 @@ chongming/routes/<type>/__meta__ # 插件级元信息(可选,仅在声
| `docstring` | string | `""` | OpenAPI 描述 |
| `timeout` | number | `3.0` | 单次调用超时(秒);流式端点为其**总寿命上限**,须配大(如 300) |
| `cacheable` | bool | `false` | 网关侧结果缓存开关(成功响应按 `(type, subject, payload)` 缓存) |
| `validate` | bool | `true` | 网关是否解析并校验请求体(false = 原样透传,校验下沉 worker;仅对 POST/PUT/PATCH 非流式端点生效,见 §4.2) |
| `auth_required` | bool | `true` | 网关是否注入鉴权依赖(认证用户经信封 `meta.user_info` 透传给插件) |
| `internal` | bool | `false` | 内部端点:不注册 HTTP 路由,仅保留 Zenoh RPC 调用能力 |
| `stream` | bool | `false` | 流式端点:网关以 SSE 逐块转发多回复 |
@@ -147,17 +148,33 @@ worker/<type>/<id>/<subject>
**兼容规则**:非信封载荷(不含 `meta`/`data` 键的 JSON 对象)整包视为业务 `data`,按 `method = GET` 处理。
**透传模式(`validate = false` 端点)**:`data` 为请求体的**原始 JSON 值**(网关零解析/校验,
信封由字节拼接构造,结构不变)。插件收到的 `data` 形态与校验模式一致(由 SDK 解析为 dict);
参数类型转换/校验失败由插件侧暴露(框架异常经 `reply_err` → 网关 503)。空/空白请求体兜底为 `{}`。
### 4.3 响应
| 形态 | 行为 |
| ---- | ---- |
| 普通 | 单个回复,载荷为业务结果 JSON 对象 |
| 异常(非流式) | 单个回复:`{"result": 0.0, "operation": "error", "error": "<异常信息>", "worker": "<worker_id>"}` |
| 流式 | 对同一 Query **多次 reply** 逐块推送;生成器正常结束 = 流结束(无结束哨兵);中途异常以 `{"error": "<异常信息>"}` **收尾块**结束流;查询已终止(客户端断开)时停止回复 |
| 框架异常(非流式) | 单个 **`reply_err`** 回复,载荷 `{"result": 0.0, "operation": "error", "error": "<异常信息>", "worker": "<worker_id>"}`;网关据此零解析判定失败 → 重试 → HTTP 503 |
| 业务错误 | 普通回复(如 `{"code": 1, "error": "..."}`),HTTP 200 透传,网关不解析 |
| 流式 | 对同一 Query **多次 reply** 逐块推送;生成器正常结束 = 流结束(无结束哨兵);中途异常以 `{"error": "<异常信息>"}` **收尾块**结束流(流式错误仍为普通回复,不走 `reply_err`);查询已终止(客户端断开)时停止回复 |
> **错误通道分层**:框架异常(handler 抛错、无匹配方法、超时)→ `reply_err`;
> 业务错误(业务逻辑判定失败)→ 普通回复。插件作者语义:**返回即业务、抛出即框架**。
>
> **兼容矩阵**(新旧网关/插件任意组合均语义完好):
>
> | 网关 \ 插件 | 旧(普通回复错误信封) | 新(reply_err) |
> | ----------- | ---------------------- | --------------- |
> | 旧 | HTTP 200 + 错误信封(历史行为) | `call()` 已处理 reply.err → 重试 → 503 |
> | 新 | HTTP 200 + 错误信封(透传不解析,业务语义) | reply_err → 重试 → **503**(语义修正) |
网关侧对应行为:
- 普通调用 `WorkerManager.call`:取首个回复;空回复 / zenoh 层错误 / 超时 → **切换副本重试**(默认重试 1 次)
- 普通调用 `WorkerManager.call_raw`(HTTP 端点):取首个回复,**原始字节零解析透传**给 HTTP 响应;空回复 / reply.err / 超时 → **切换副本重试**(默认重试 1 次),重试耗尽 → HTTP 503
- `call()`(MQTT Bridge 等内部调用方):同上述重试逻辑,回复解析为 dict 后使用
- 流式调用 `WorkerManager.call_stream`:逐块消费(`ConsolidationMode.NONE`);收到含 `error` 键的块视为终止信号转发后结束;`reply.err`(zenoh 层错误)同样终止流
- 无可用副本 → HTTP 503
@@ -204,6 +221,13 @@ worker/<type>/<id>/<subject>
- **协议变更分级**:
- 破坏性变更(keyexpr 结构、信封结构、错误格式、描述符语义)→ `schema_version` 递增,网关须先发布兼容处理,再切换
- 新增可选字段 / 新增端点形态 → 允许同版本内演进,但必须同步更新本规范
- **本版同版本内演进说明(2026-08)**:
- 新增描述符字段 `validate`(§2.2,网关缺失时兜底 true,纯增量)
- 非流式框架异常新增 `reply_err` 错误通道(§4.3):信封结构与错误载荷均不变,
仅输出通道由普通 reply 改为 reply_err;网关 `call()/call_raw()` 历史上已处理 reply.err,
新旧组合兼容(见 §4.3 兼容矩阵),故不递增 schema_version
- 网关普通调用由 `call`(dict 语义)切换为 `call_raw`(bytes 透传):入参出参形态变化
为网关内部实现,不影响线上协议
- **修改即更新**:任何实现侧改动(`routes_publisher.py` / `runtime.py` / `route_registry.py` / `worker_manager.py` / `route_generator.py`)触及本规范描述的语义时,必须同步修订本规范
---
+11
View File
@@ -240,6 +240,17 @@ from . import hello
__all__ = ["hello"]
```
**异常语义**(插件作者只需 return / raise,通道由 SDK 处理):
| 形态 | 插件写法 | 网关行为 |
| ---- | -------- | -------- |
| 业务错误 | `return {"code": 1, "error": "..."}` | HTTP 200 透传(业务语义,网关不解析) |
| 框架异常(非流式) | `raise ValueError(...)` | SDK 经 `reply_err` 通道回复 → 网关重试后 **HTTP 503** |
| 流式异常 | 生成器内 raise | SDK 发送 `{"error": ...}` 收尾块 → SSE error 事件终止 |
即「**返回即业务、抛出即框架**」。注意:框架异常从历史行为「HTTP 200 + 错误信封」
修正为 **503**(`reply_err` 通道,见 wire 协议 §4.3 兼容矩阵)。
### 第 6 步:本地调试
```bash