aps-agent/docs/integrations/mes-http.md

7.5 KiB
Raw Permalink Blame History

真实 MES HTTP 适配器(config-driven)

round-45 方向 II · 验收矩阵 73/75 推进(round-46 方向 LL:对接就绪检查 readiness) 模块:server/integrations/mes_http.py(integ-mes-http,可复用 ✔)

目标

  • 矩阵 73(「对接至少一个真实 MES 测试环境;鉴权、幂等、超时、重试、回执和补偿通过」): 真实工厂需外部环境,本轮以 config-driven HTTP MES 适配器框架 落地——HttpMesClient 可指向任意 base URL 的真实 MES,用本地 HTTP stub 黄金测试覆盖鉴权/幂等/超时/重试/回执。
  • 矩阵 75(「真实 MES/WMS 适配器(现场对接)」):适配器已注册进 MCP 总线 (plugin mes.http,工具 mes.http_dispatch 等 + power 门禁),现场对接只需配置。

与 Mock stub 的切换

  • 默认 = 进程内 Mock(server/integrations/mes_stub.py,MockMesClient),不依赖任何网络。
  • 显式配置 MES_HTTP_BASE_URL 后 = HTTP 适配器:server/aps_domain/mes.py 的 _get_active_client() 按环境变量选择客户端,接口完全一致(status / create_work_order / post_report / cancel_work_order),mes.dispatch P3 门禁与 mes.cancel_dispatch saga 补偿路径不受影响。
# 启用 HTTP 适配器(现场/联调环境)
export MES_HTTP_BASE_URL=https://mes.example.com/api
# 切回本地 Mock(默认):不设置 MES_HTTP_BASE_URL 即可

环境变量

变量 默认 说明
MES_HTTP_BASE_URL (空 = fail-closed) 真实 MES / 本地 stub 的根地址,如 http://127.0.0.1:8765
MES_HTTP_TOKEN 空 鉴权 token;配合 MES_HTTP_TOKEN_HEADER 使用
MES_HTTP_TOKEN_HEADER Authorization token 所在头;Authorization 自动补 Bearer 前缀
MES_HTTP_TIMEOUT_SECONDS 10 单次请求超时(秒)
MES_HTTP_MAX_RETRIES 2 指数退避重试次数(连接失败/超时/5xx/429;4xx 不重试)
MES_HTTP_IDEM_HEADER X-Idem-Key 幂等键所在头(也可放 body.idemKey)

token 仅由 HttpMesClient 从环境/构造参数读取,不写入 plugins.json(MCP manifest 的 auth 字段保持为空)。

端点约定(适配器 → MES)

操作 方法/路径 说明
健康/连接 GET /health 返回 {ok, system, plant, woCount, ...}
下发(幂等) POST /work-orders body 携带工单数据 + idemKey;重复 idemKey 返回 {duplicate:true, externalWo}
状态查询 GET /work-orders/{externalWoId} 外部工单状态轮询
报工回执 POST /work-orders/{externalWoId}/reports 回流 progressPct/qtyDone/status
撤单(幂等) POST /work-orders/{externalWoId}/cancel saga 补偿;重复撤单返回 duplicate:true

失败语义(供 saga 补偿)

MesHttpError{code, status_code} 显式抛出,mes.cancel_dispatch 会把 HTTP 失败记为 failed("<CODE>:<externalWoId>")而不是静默跳过:

code 触发
MES_HTTP_NOT_CONFIGURED 未配置 MES_HTTP_BASE_URL(fail-closed)
MES_HTTP_CONNECT_FAILED / MES_HTTP_TIMEOUT 连接失败 / 超时(重试耗尽后)
MES_HTTP_AUTH_FAILED 401/403 鉴权失败
MES_HTTP_UPSTREAM_ERROR 5xx/429(重试耗尽后)
MES_HTTP_NOT_FOUND / MES_HTTP_REJECTED / MES_HTTP_INVALID_RESPONSE 404 / 其他拒绝 / 响应不合法

MCP 总线注册(矩阵 75)

  • 总线启动即注册 plugin mes.http(manifest + 工具契约 + power 门禁,fail-closed):
工具 权力 幂等 说明
mes.http_dispatch P3 ✔ 真实 MES 下发(需显式放行权限)
mes.http_status P0 ✔ 连接/外部工单状态(只读)
mes.http_report P2 ✘ 报工回执
mes.http_cancel P2 ✔ 撤单(saga 补偿)
  • P2/P3 写工具默认 deny,调用前需 set_permission(plugin="mes.http", tool=..., allow=True); 未配置 MES_HTTP_BASE_URL 时任何工具调用抛 MesHttpError MES_HTTP_NOT_CONFIGURED(fail-closed)。

对接就绪检查(readiness,矩阵 73 现场对接准备)

HttpMesClient.readiness(probe=False) 返回稳定 JSON 字段(前端可直接展示,不抛错):

字段 类型 说明
configured bool 是否已配置 MES_HTTP_BASE_URL(fail-closed)
baseUrl string/null 当前 base URL;未配置为 null
tokenPresent bool 是否已配置 MES_HTTP_TOKEN
timeoutSec number 单次请求超时(秒)
maxRetries int 重试次数
connectivity "unknown"/"ok"/"failed"/null 未配置 null;配置未探测 unknown;探测后 ok/failed
lastError {code,message,statusCode}/null 探测失败时记录最近一次错误,成功/未探测为 null
message string 中文提示(如「未配置 MES_HTTP_BASE_URL」「连通正常」)
  • readiness()(不探测):只返回配置视图,connectivity="unknown",不发网络请求。
  • readiness(probe=True):对 base_url 发轻量 GET /health,短超时(min(timeout, 3s)); 失败不抛错,记录 connectivity="failed" + lastError。
  • 未配置时 configured=false,connectivity=null,message 明确提示(网关 200 不 500)。

网关端点

方法/路径 权力 说明
GET /api/integrations/mes/readiness P0 只读 返回 readiness() 配置视图
POST /api/integrations/mes/readiness/probe P1 触发一次连通性探测(GET /health 短超时)
curl -s http://127.0.0.1:8003/api/integrations/mes/readiness
# {"configured":false,"baseUrl":null,"tokenPresent":false,"timeoutSec":10.0,
#  "maxRetries":2,"connectivity":null,"lastError":null,"message":"未配置 MES_HTTP_BASE_URL:..."}

现场对接步骤

  1. 获取真实 MES 的 base URL 与 token,配置 MES_HTTP_BASE_URL / MES_HTTP_TOKEN。
  2. 对齐端点:若真实 MES 路径不同,改写 HttpMesClient 各方法中的 path 常量即可(框架已隔离)。
  3. 校验:GET /api/integrations/mes/readiness 返回 configured=true, POST /api/integrations/mes/readiness/probe 返回 connectivity="ok"; mes_connection_status() 返回 mode=http, connected=true。
  4. 权限放行:管理台/API 对 mes.http_dispatch 等工具 allow=True。
  5. 联调:小批量下发 → 验证 MES 侧工单创建;重复 idemKey 验证幂等;断网/5xx 验证超时重试与补偿。

测试

.venv\Scripts\python.exe -m pytest tests/golden/test_mes_readiness.py tests/golden/test_mes_http.py tests/golden/test_mes.py -q
  • 本地 stub:FastAPI + uvicorn,随机端口(不占用 8003/5173)。
  • 黄金覆盖:readiness(未配置 fail-closed / 字段齐 / 探测 ok/failed / 网关接线)+ 正常下发+回执 / 幂等 / 超时 / 5xx 重试恢复 / 重试耗尽 / 鉴权失败 / fail-closed / mes.py 域切换(stub 默认,HTTP 显式)/ MCP 总线端到端。

边界与剩余风险

  • 矩阵 73 的真实工厂对接仍需外部环境:本轮的 HTTP 框架 + 本地 stub 黄金测试覆盖了 鉴权/幂等/超时/重试/回执/补偿的适配器侧语义;真实 MES 端点路径/报文差异需现场配置联调。
  • 适配器假设 MES 侧以 idemKey 头/字段去重;真实 MES 若用不同幂等协议需在 create_work_order 内适配。
  • token 经环境变量注入,未做密钥管理(生产可接入 KMS/Secrets 提供方)。