← 全部范例范例 03
处理无结果与重试,且不会重复付费
你将构建: 一个调用包装器,区分三种结果 —— 找到、没找到、失败 —— 且只重试第三种,并用幂等键确保重试绝不会重复扣费。
| 分类 | API 基础 |
|---|---|
| 使用的操作 | POST /v1/data/contacts/find-email |
| 积分 | 5 (最坏情况) |
| 测试密钥可用 | 是 —— 可在 qk_test_ 上运行,零积分 |
| 预计耗时 | ~10 分钟 |
| 前置条件 | 一把密钥,以及能设置请求头的客户端。 |
是三种结果,不是两种
找到的结果是 HTTP 200,data 有内容,扣费非零。没找到是 HTTP 200,data: null,X-Credits-Charged: 0 —— 查询如实执行了却一无所获,所以未计费。失败则是 4xx 或 5xx。只有第三种值得重试。
three outcomes
# FOUND — data populated, charged
# < 200 X-Credits-Charged: 5
{ "status": "OK", "data": { /* … */ } }
# MISS — ran honestly, found nothing, billed zero
# < 200 X-Credits-Charged: 0
{ "status": "OK", "data": null }
# FAILURE — nothing billed, safe to retry
# < 503不要重试「没找到」
「没找到」是关于世界的真实答案,而非瞬时错误。重试并不会凭空变出结果,只会增加延迟。把它缓存一段合理时间,然后继续往下走。
branch.py
# Branch on the payload BEFORE the status code:
# a miss and a hit are both HTTP 200.
if res.status_code >= 500:
return retry_later() # transient
if res.json()["data"] is None:
cache_miss(query, ttl=86_400) # a real answer — do not retry
return None
return res.json()["data"]用幂等键重试失败
数据端点接受 Idempotency-Key 请求头。为每个逻辑操作发送一个稳定的键,超时后的重试就会落到原始结果上,而不是第二次计费调用 —— 在你根本没看到第一次响应时,这一点最为要紧。
idempotent.sh
# A stable key per logical operation. If you never saw the first
# response, the retry resolves to it instead of billing twice.
curl -X POST https://api.qannasapi.com/v1/data/contacts/find-email \
-H "Authorization: Bearer $QANNAS_API_KEY" \
-H "Idempotency-Key: signup-8f21c4" \
-H "Content-Type: application/json" \
-d '{"query": "Jane Doe, Acme Logistics"}'退避重试,且绝不重试 4xx
对 5xx 和超时采用指数退避加抖动进行重试。422 意味着请求体有误:请修正它,而不是重发。上游故障从不计费,因此真正失败后的重试不会让你多花一分钱。
retry.py
import random, time
def call_with_retry(send, *, max_attempts=5):
for attempt in range(max_attempts):
res = send()
if res.status_code == 422:
raise ValueError(res.text) # malformed — never resend
if res.status_code < 500:
return res
# 5xx: upstream failures are never billed, so retrying is free
time.sleep(0.5 * 2 ** attempt + random.uniform(0, 0.5))
raise RuntimeError("exhausted retries")小结
| 模式 | 做法 |
|---|---|
| 找到 | 200,data 有内容,X-Credits-Charged > 0 |
| 没找到 | 200,data: null,X-Credits-Charged: 0 —— 不要重试 |
| 失败 | 4xx / 5xx —— 只重试 5xx 与超时 |
| 安全重试 | Idempotency-Key 请求头,每个逻辑操作保持稳定 |
| 请求有误 | 422 —— 修正请求体,绝不原样重发 |
| 退避 | 指数退避加抖动,并限制尝试次数 |
上线检查清单
- 先按 data == null 分支,再按状态码分支。
- 凡是可能重试的调用都带上 Idempotency-Key。
- 重试 5xx 与超时;绝不重试 422。
- 缓存无结果,避免一整天反复问同一个问题。
下一步
先运行预估。它不花任何费用,用的正是计量器将要套用的那套算术。