先看现象。图像生成服务要求客户端带 Idempotency-Key,代码里用 uuid4 在每次请求时现生成,网络抖动重试后服务端当成新请求,同一张图扣了两次费。
原因不止一个,得分开看。幂等键在重试分支里被重新生成。也可能是键里混入时间戳或随机数,天然不唯一。
另外,SDK 层自动重试时没有复用原键。
少数情况下是键由前端生成,刷新页面后取值变化。
动手时先确认重试时键是否变化
python -c "import uuid;print(uuid.uuid4(), uuid.uuid4())"
再往下把键提到请求入口按业务单号生成
python -c "import hashlib;print(hashlib.sha256('order-20261113-001'.encode()).hexdigest()[:32])"
接着关闭 SDK 自动重试改为显式重试
curl https://api.example.com/v1/images -H "Idempotency-Key: 8f14e45fceea167a5a36dedd4bea2543" -H "Authorization: Bearer $KEY" -d @img.json
末了用同一个键连发三次验证只生成一张
python -c "import requests;h={'Idempotency-Key':'8f14e45fceea167a5a36dedd4bea2543'};print([requests.post('https://api.example.com/v1/images',headers=h,json={'prompt':'cat'}).status_code for _ in range(3)])"
怎么算真的好了,看的是同一批现象。同一个键连发三次只产生一条任务记录,账单只扣一次,重试请求返回首次结果而不是报重复。
这里还有个坑。幂等键的生命周期要覆盖整个重试链路,放在请求函数内部生成等于没有幂等,正确的做法是从业务单号推导。报错文案容易误导,真正的原因往往在相邻那一层的日志里。
