# 重试之前,先查清订单到底有没有创建 | EasyNet Source: https://easynet.run/cases/problems/retry-without-duplicate-order [easynet.run · 全部问题场景](https://easynet.run/cases#problem-scenarios) # 重试之前,先查清订单到底有没有创建 采购助手提交补货单后显示超时,采购员点了重试。过一会儿,两张相同订单都出现在供应商后台。第一次失败的可能只是回复,不是创建动作;屏幕上的等待结束,并没有替业务决定订单是否存在。 订单平台已有幂等键和状态查询时,应先使用它们。只有一个服务的场景,用事务和唯一约束更直接。EasyNet 不提供一个能替代这些保证的回执;它的作用是多个助手经过同一操作入口时,保留可追踪的尝试与调用身份。 适配器需要提供两个明确动作:提交这次购买意图,以及查询这次购买意图的结果。提交输入包含业务认可的稳定请求键、商品和数量;重试仍用同一业务键。调用记录的标识可以关联业务键,但两者不是天然等价,更不能每次重试都新建一笔意图。 查询返回应区分处理中、已创建、明确未创建和暂时无法确认。得到订单号后,助手展示的是原系统记录;查不到而又无法排除已提交时,进入待核对,不擅自创建第二单。业务键相同而数量变化,也必须让适配器拒绝或要求重新确认。 上游订单凭据留在提供方,调用者的权限只覆盖自己的采购范围。谁能下单、谁能查询,仍由业务适配器和授权共同检查。取消、退款是另一个有副作用的操作,不能因为原请求超时就自动执行补偿。 验证时刻意让订单已经落库、回复却丢失,再让同一采购范围内获准的第二个调用者查询原业务请求。确认只有一张订单,也确认不同参数不能被同一个键悄悄接受。业务幂等、查询和对账尚需按订单系统实现;这个方案要消除的是“未知就再做一次”,不是宣称网络调用永远只执行一次。 01 提交补货意图 固定业务键和数量 02 回复丢失 显示未知,不宣告失败 03 查询原订单 同一业务键取回原订单号 丢失回复后查原请求,不产生第二个购买意图。 同一键的参数必须一致 进程内示例只演示参数冲突检查;生产需持久事务与上游认可的幂等实现,不是网络一次执行保证。 本地示例 · python ``` orders = {} def submit(key, item, quantity): intent = (item, quantity) if key in orders: if orders[key]["intent"] != intent: raise ValueError("request key reused with different input") return orders[key]["order_id"] orders[key] = {"intent": intent, "order_id": "order-001"} return "order-001" submit("restock-2026-09-A", "paper", 10) # reply lost assert submit("restock-2026-09-A", "paper", 10) == "order-001" assert len(orders) == 1 try: submit("restock-2026-09-A", "paper", 20) except ValueError as error: print(error) ``` 预期结果:保留一条记录;改成 20 件时输出参数冲突,不能悄悄接受。 接入时的检查项 模拟服务已提交但客户端未收到回复,是否仍只生成一笔业务记录。 相同业务键携带不同参数时是否明确拒绝。 未知状态是否不会被显示为已取消或已退款。 源码与接入资料 [函数接入指南](https://easynet.run/docs/connect/function) [设备接入指南](https://easynet.run/docs/connect/runtime)