仓库收到了三次相同订单
目标
实现一个 Python CLI,用于验证客户的合成订单 CSV,并在虚拟仓库中创建预留。 即使重复运行同一文件或响应丢失,也不得重复创建预留,并应交接未解决项目。
为什么重要
API 调用成功与客户业务完成不是一回事。未收到响应时一律重发,可能会再次创建已经保存的订单。 反之,如果完全禁止重试,又会丢失在保存前失败的正常订单。本练习同时处理输入契约、幂等键、持久化账本和重试上限。 这是一个没有真实出库、支付或客户信息的虚拟机器人零件仓库。不得直接读取或修改对方账本文件,只能通过 HTTP 契约集成。
预计耗时 80 分钟。请在默认 60 分钟会话结束前使用“+时间”延长(最长 180 分钟)。 会话结束后,/root/handoff 中的文件会消失。请在结束前将所需代码另存到个人工作区。
材料与执行契约
- 客户简报:/opt/data/handoff-brief.md
- CLI、报告与交接文档契约:/opt/data/handoff-program-contract.md
- 合成订单:/opt/data/handoff-orders.csv
- 起始代码:/opt/data/handoff-sync-starter.py
- 执行评估器:/opt/lab/handoff/evaluate.py
先阅读简报和执行契约。输入最大为 256KiB、100 行,数量为 1~5 个字符。 只将未被搁置的订单按 API 正文 order_id、sku、quantity 准备。邮件地址不得包含在传输、日志或报告中。 向评估器传递程序路径,以及 plan/send/chaos/repeat/drift/outage 中的检查名称。 示例:python3 /opt/lab/handoff/evaluate.py /root/handoff/sync.py plan 评估器会创建隔离的临时数据和服务器并自行关闭,因此无需提前启动单独服务器。 评估数据会更改部分订单号、SKU 和数量。不要硬编码所提供 CSV 的结果。
步骤
- 创建 /root/handoff,并将起始代码复制为 sync.py。在 scope.json 中记录业务 warehouse-reservation、业务键 order_id、send_pii=false、max_attempts=4、retryable_statuses=[503]、conflict_policy=hold_order、approval=review_only。JSON 的键名为 workflow、business_key、send_pii、max_attempts、retryable_statuses、conflict_policy、approval。
- 在 sync.py 中实现完整 CSV 验证和计划报告。默认模式发送 0 次 HTTP 请求,outcomes 为空数组。同一订单中出现无效行或冲突时,整个订单都应搁置;内容相同的行只将第一行列为候选,其余归入 duplicates。使用 plan 检查确认。
- 实现 sync.py 的 --send 分支。在正常服务器上只 POST 候选订单,并通过 GET /orders/<订单编号> 确认恰好有一个预留,且其内容与 ID 正确。报告的七个字段、outcomes 的四个字段以及退出码 0/2 均遵循执行契约。使用 send 检查与实际账本核对。
- 在 sync.py 中实现每次请求 1 秒超时、保持相同订单键,对 503 和连接错误最多尝试四次且间隔 0.1 秒。通过 chaos 检查,处理保存前返回 503 和保存后响应丢失两种情况。4xx 不得重试。
- 确认 sync.py 在下一次执行中仍使用相同业务键。repeat 检查会使用同一账本重启服务器,并再次执行相同输入。如果新增预留数量增加或 ID 变化,请修正每次执行都会变化的键以及重试分支。
- 实现 sync.py,确保已预留订单的数量发生变化时,不会通过新键绕过冲突。drift 检查会在第二次执行中更改部分数量。遇到 409 时,只进行一次 POST 就停止,结果保留为 rejected 和 null,并维持现有预留。
- 确认持续返回 503 时,sync.py 会在每个订单完成四次 POST 后停止,并记录 unconfirmed 和 null。运行 outage 检查。无法通过查询确认的结果也不得标记为成功。
- 使用当前实现运行全部六项检查,生成 handoff.json。使用评估器的 receipt 模式,记录实现与样本哈希、案例列表、review_only 决定、未解决的无效数量与冲突订单,以及实验限制。最终评分会同时读取 scope.json、sync.py 和 handoff.json,并重新验证执行情况。
参考
- 计划模式自行执行示例:python3 /root/handoff/sync.py --input /opt/data/handoff-orders.csv --base-url http://127.0.0.1:8031 --report /root/handoff/plan.json
- 上述计划模式不会连接服务器。若要直接测试 --send,请先使用简报中的虚拟 API 启动命令。
- 生成交接文档:python3 /opt/lab/handoff/evaluate.py /root/handoff/sync.py receipt > /root/handoff/handoff.json
- 实现发生变化后,也必须重新验证并生成交接文档。不要只修改哈希。
- 验证成功不等于获得生产批准。这只是单个合成仓库,也不是用于阻止同一 UID 下恶意程序的独立安全边界。
从客户描述中固定工作范围
请区分业务键和传输事件。发生冲突时,不要由工程师选择数量,而应搁置整个订单。
发送前对七行数据分类
使用 csv.DictReader 读取整个文件,按 order_id 分组后分类。CSV 解析器的默认字段限制也应与输入上限一致。如果发送前 7 行后才发现第 8 行存在冲突,就已经太晚了。
通过查询确认正常预留
对比 POST 响应与 GET 账本中的 ID、SKU 和数量。发送结果中仍有搁置项时,使用退出码 2 表示。
恢复保存前失败与响应丢失
始终使用相同的 order_id 作为幂等键。错误类型、尝试次数和业务确认状态彼此独立。
由下一位负责人重新运行同一文件
检查键中是否混入当前时间或本次执行的 UUID。不仅现有预留数量必须相同,ID 也必须相同。
不要将变化后的数量伪装成新订单
若将正文哈希用作键,数量变化时会创建新预留。遇到 409 时,不要重试或替换键,而应将其保留为拒绝结果。
仓库持续故障时停止
即使达到最大尝试次数,也不要改为成功状态。未经确认的预留 ID 应为 null。
交接执行依据与未解决项目
使用 receipt 模式重新验证当前代码。修改代码后,不要只修改哈希,而应重新执行验证。