QannasAPI

处理无结果与重试,且不会重复付费

你将构建: 一个调用包装器,区分三种结果 —— 找到、没找到、失败 —— 且只重试第三种,并用幂等键确保重试绝不会重复扣费。

分类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。
  • 缓存无结果,避免一整天反复问同一个问题。

下一步

先运行预估。它不花任何费用,用的正是计量器将要套用的那套算术。