跳到正文
ArchiveZaunEkko Docs
阅读设置
正文字号
字体
简体中文English
展开文档目录

实现你的服务

状态
生效中
更新
2026-09-13
适用范围
API Platform 提供方实现与一致性检查

你的服务需要暴露四个入口。平台调用它们,你返回一个固定形状的信封。

本页讲怎么实现,以及提交通道后平台会检查什么、每条不通过意味着什么。

四个入口

GET  /health/live          进程活着
GET  /health/ready         自身配置与依赖可用
POST /v1/executions        执行一次调用
POST /v1/reconciliations   查询某次调用的真实结局

健康检查不要求凭据。另外两个必须校验平台带来的 Authorization: Bearer 凭据——那把凭据只属于你这一条通道,泄露它等于把执行入口对外开放。

就绪检查表示你自己可用,不要在里面反查平台。平台不可用时你无需也不应报告未就绪。

执行

POST /v1/executions
Authorization: Bearer <平台配置给你的凭据>
Idempotency-Key: <平台生成的稳定标识>
Content-Type: application/json
{ "payload": { "你在商品契约里定义的字段": "值" } }

payload 是一个非空 JSON 对象,内容由你的商品契约决定。信封本身只有这一个顶层字段,出现未知顶层字段必须拒绝。

返回信封

无论成功失败,都返回同一个形状:

{
  "outcome": "SUCCEEDED",
  "correlationId": "你自己的任务号",
  "result": { "业务结果": true },
  "errorCode": "",
  "httpStatus": 0
}

不适用的字段省略。四种结局,HTTP 状态码必须与之匹配:

outcomeHTTP 状态含义平台会怎么做
SUCCEEDED任意 2xx业务已完成且结果已持久化结算扣费
DEFINED_FAILURE与 httpStatus 相同的 4xx/5xx业务确定失败释放冻结的积分,不扣费
RETRYABLE_BEFORE_ACCEPT精确 503你能确证尚未受理这次调用有限次重发
UNKNOWN_OUTCOME精确 202可能已受理,结局未定只对账,绝不重发

DEFINED_FAILURE 需要一个稳定的 errorCode(不超过 64 字符)。

不要用 DEFINED_FAILURE 表达基础设施的不确定。 它的含义是「这次业务请求确定失败了」,平台据此释放积分;如果实际上你已经执行了业务,这笔就白做了。不确定时用 UNKNOWN_OUTCOME。

超时、连接中断、非法 JSON、超长响应、状态码与 outcome 不匹配、跳转——平台一律按 UNKNOWN_OUTCOME 处理。所以凡是你已经受理的调用,都必须能通过对账查到。

幂等

平台每次调用带一个稳定的 Idempotency-Key。你需要:

  1. 对收到的 payload 原始字节算一个指纹,和这个 key 绑定存起来;
  2. 同 key 同指纹再来时,返回已存的结果,不要重新执行业务;
  3. 同 key 不同指纹时,返回 DEFINED_FAILURE,httpStatus 与 HTTP 状态都用 409,并且不修改原记录。

存储必须是持久的。进程重启后,同一个 key 的对账仍然要能返回之前受理的结果——内存里的 map 空了不等于没受理过。

顺序也重要:在执行业务副作用之前(或在同一个原子操作里)先落盘「已受理」标记,返回响应之前落盘最终结局,事务提交完成之后再写 HTTP 响应。

对账

POST /v1/reconciliations
{ "providerIdempotencyKey": "平台之前用过的那个 key" }

对账永远不启动业务执行,它只读你已经存下来的记录。

查不到就返回成功是最危险的实现。 那等于凭空宣称完成了一次没发生的业务,平台会据此扣走调用方的积分。

提交后平台会检查什么

通道提交后,平台会调用你的端点跑一次契约一致性检查,结果直接显示在你的通道页面上。你可以自己反复运行——改实现、重跑、看哪条还红,不必等任何人。

检查会在你的服务上产生一次真实调用。它使用与正式调用不同的 Idempotency-Key 前缀(ekko-conformance:),你可以据此识别;这次调用不产生回执、不冻结也不扣任何积分。

检查不了解你的业务:它发一个明确无意义的 payload,SUCCEEDED 和 DEFINED_FAILURE 都算合格。它验的是信封形状、幂等语义和凭据校验,不是业务成功——你能用带 errorCode 的 DEFINED_FAILURE 干净地拒绝垃圾输入,本身就是合规的证明。

九项检查

检查不通过意味着
存活探测/health/live 不可达或非 2xx
就绪探测/health/ready 不可达或非 2xx。注意它不该依赖平台
执行面校验凭据不带凭据也能调用你的执行入口。 任何人都能直接驱动你的业务
执行响应信封合规返回的 outcome 不在四种之内,或 HTTP 状态与 outcome 不匹配
同 key 重放稳定同 key 同 payload 重放返回了不同结果,说明业务被重复执行了
同 key 换 payload 冲突没有按 409 拒绝,说明幂等记录没有真正绑定 payload 指纹
拒绝未知 envelope 字段你接受了契约之外的顶层字段。将来协议演进时,你会照单全收却不理解新字段
已知 key 可对账刚受理过的 key 对账查不到,或返回了 RETRYABLE_BEFORE_ACCEPT——后者会让平台重复执行
未知 key 不谎报成功从未提交过的 key 对账返回了 SUCCEEDED

关于「已跳过」

某一项显示已跳过时,它既不是通过也不是失败,而是没有验过。

比如执行入口本身没跑通,后面三项幂等检查就没有可比对的基线,会全部跳过。这时不要去查幂等实现——先修好前面那一项,重跑之后它们才会给出真实结论。

检查与上架的关系

技术核验通过是上架的前置条件。检查未通过的通道不会被批准。

通道的地址或标识变更后,之前的检查结果失效,需要重新运行。

检查通过不等于已上架。 它只说明技术契约没问题;商品是否适合上架是另一道业务判断。

一份最小实现的骨架

以下用伪代码表达顺序,语言不限:

POST /v1/executions:
  校验 Authorization,不通过 → 401
  解析信封,出现未知顶层字段 → 400
  fingerprint = 对 payload 原始字节取哈希

  事务开始
    record = 按 key 加锁读取
    若 record 存在:
        若 record.fingerprint != fingerprint → 409 DEFINED_FAILURE
        否则 → 返回 record 里存着的结局      // 不重新执行
    否则:
        写入「已受理」标记(key, fingerprint)
  事务提交

  执行业务
  持久化最终结局与 correlationId
  返回响应

对账只做「按 key 读取并返回」,没有任何写入。

检查覆盖不到的部分

检查验的是信封形状、幂等语义与凭据校验。重试、超时、结果超限这类失败路径无法从外部触发,因此不在检查范围内——九项全绿不代表这些路径也对。它们同样是契约要求,仍需你自行保证。

一致性检查没有可下载的离线版本,提交通道后在通道页面触发即可。

协议与本页描述不一致时,以平台实际接口行为为准。入驻流程见成为服务提供方,当前缺口见目前的限制。