跳转到内容

第三方接口调用规范

超时、重试、熔断、降级


[Requirement] 所有第三方调用必须设置连接超时和读取超时,禁止使用默认无限超时。

超时类型建议值说明
连接超时(Connect)1~3 秒建立 TCP 连接的时间
读取超时(Read)3~10 秒等待响应数据的时间
整体超时(总)不超过 10 秒单次调用总耗时上限

[Standard] 超时时间按接口 SLA 配置,慢接口可适当放宽但必须有上限;禁止为”调通”而设置超大超时。

import httpx
 
# 正确:分层超时
client = httpx.Client(
    timeout=httpx.Timeout(
        connect=2.0,
        read=5.0,
        write=2.0,
        pool=2.0,
    ),
    limits=httpx.Limits(max_connections=20, max_keepalive_connections=5),
)
// OkHttp 示例
OkHttpClient client = new OkHttpClient.Builder()
    .connectTimeout(2, TimeUnit.SECONDS)
    .readTimeout(5, TimeUnit.SECONDS)
    .writeTimeout(2, TimeUnit.SECONDS)
    .callTimeout(10, TimeUnit.SECONDS)   // 总超时
    .build();
# 反模式:无超时
requests.get(url)                    # 可能永久阻塞
requests.get(url, timeout=300)        # 超时过大,拖垮线程池

[Standard] 仅对幂等接口和瞬时错误重试,写操作(POST/PUT/PATCH)默认不重试,除非接口支持幂等键。

错误类型是否重试说明
网络超时、连接拒绝是瞬时网络问题
HTTP 5xx是服务端故障
HTTP 408 / 429是(带退避)超时/限流
HTTP 4xx(除 408/429)否参数/权限错误,重试无意义
业务错误码否业务逻辑问题

[Requirement] 重试必须使用指数退避 + 抖动(Exponential Backoff with Jitter),禁止固定间隔重试。

重试间隔 = min(base * 2^retry_count, max_interval) + random_jitter

[Default] 默认重试 3 次,初始间隔 100ms,最大间隔 2s,总耗时不超过 5s。

import random, time
 
def call_with_retry(func, max_retries=3, base_delay=0.1, max_delay=2.0):
    for attempt in range(max_retries + 1):
        try:
            return func()
        except (TimeoutError, ConnectionError) as e:
            if attempt == max_retries:
                raise
            delay = min(base_delay * (2 ** attempt), max_delay)
            delay += random.uniform(0, delay * 0.1)  # 抖动
            time.sleep(delay)

[Caution] 对写接口重试必须携带幂等键(Idempotency-Key),由调用方生成唯一 UUID,服务端据此去重。

POST /api/v1/orders HTTP/1.1
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000

[Standard] 使用熔断器(Circuit Breaker)防止级联故障,状态机三态:Closed → Open → Half-Open。

状态行为触发条件
Closed(关闭)正常调用默认状态
Open(打开)直接拒绝,快速失败错误率超阈值(如 50%,近 10s 内 ≥20 次请求)
Half-Open(半开)放行少量探测请求Open 持续冷却时间(如 30s)后

[Default] 熔断器配置:错误率阈值 50%、最小请求数 20、统计窗口 10s、冷却时间 30s、半开探测请求数 3。

# pybreaker 示例
import pybreaker
 
breaker = pybreaker.CircuitBreaker(
    fail_max=10,                # 连续失败次数
    reset_timeout=30,           # 冷却时间(秒)
    state_storage=pybreaker.CircuitMemoryStorage(),
)
 
@breaker
def call_remote_payment(order):
    return payment_client.pay(order)

[Standard] 熔断打开时调用方应捕获 CircuitBreakerError,走降级逻辑,不应向上抛出导致整个请求失败(除非核心链路)。


[Requirement] 非核心依赖必须有降级方案,核心依赖降级后需保证最终一致(通过消息队列异步补偿)。

降级类型适用场景实现
兜底数据查询类返回缓存/默认值
异步补偿写操作失败入 MQ,后台重试
功能开关非核心功能关闭该功能,主流程继续
限流排队高并发返回”稍后重试”,削峰

[Standard] 查询接口优先使用缓存兜底,缓存未命中再调用第三方;第三方失败时返回缓存(即使略旧)。

def get_user_profile(user_id):
    cache_key = f"user:profile:{user_id}"
    cached = redis.get(cache_key)
    if cached:
        return json.loads(cached)
    try:
        profile = user_client.get(user_id, timeout=2.0)
        redis.setex(cache_key, 300, json.dumps(profile))
        return profile
    except Exception as e:
        logger.warning("user service down, returning empty profile: %s", e)
        return {"user_id": user_id, "nickname": "用户", "avatar": default_avatar}

[Standard] 对核心写操作(如支付通知、订单同步),第三方失败时写入本地 MQ/数据库,由后台任务异步重试,保证最终一致。

def sync_order_to_erp(order):
    try:
        erp_client.create_order(order)
    except Exception:
        # 写入补偿表,后台扫描重试
        CompensationTask.objects.create(
            type="erp_order_sync",
            payload=json.dumps(order),
            retry_count=0,
            next_retry_at=datetime.now() + timedelta(minutes=1),
        )

[Requirement] 每次第三方调用必须记录:调用方、被调方接口、HTTP 状态码、耗时、成功/失败、异常类型。

[Standard] 指标维度:service_name、endpoint、status_code、is_success,上报到 Prometheus。

[Standard] 告警规则:

指标阈值级别
错误率> 5%(5 分钟窗口)警告
错误率> 20%(1 分钟窗口)紧急
P99 耗时> SLA 的 2 倍警告
熔断器打开任一熔断器警告

[Standard] 调用日志必须包含 trace_id、第三方接口名、耗时、请求参数(脱敏)、响应码、异常堆栈。

[Caution] 日志中禁止打印第三方返回的敏感信息(如用户隐私、密钥、完整身份证)。

[Default] 对关键第三方依赖提供 /health/upstream 端点,聚合各依赖的连通性与延迟,供运维监控。