在外部服务故障时保持应用运行的安全第三方 API 集成。学习超时、重试、断路器和快速检查。

第三方 API 的失败往往不是明显的“宕机”。最常见的问题是变慢:请求挂起、响应迟到,而你的应用一直在等待。如果这些调用处在关键路径上,外部的小问题会在你系统内部堆积。
这就是本地变慢如何演变成全面故障的原因。线程或工作进程被卡住等待,队列增长,数据库事务保持打开状态更久,新请求开始超时。不久之后,即便是不依赖外部 API 的页面也会感到故障,因为系统被等待中的任务压垮了。
影响是具体的。一个不稳定的身份提供商会阻塞注册和登录。支付网关超时会冻结结账,让用户不知道是否已被扣款。消息延迟会阻止重置密码和订单确认,从而引发第二波重试和支持单。
目标很简单:隔离外部失败,让核心工作流继续进行。那可能意味着允许用户下单,然后稍后确认支付,或即使欢迎邮件发送失败也允许注册成功。
一个实用的成功指标是:当某个提供方变慢或宕机时,你的应用仍能快速且清晰地响应,影响范围保持较小。例如,大多数核心请求仍在正常延迟预算内完成,失败仅限于真正依赖该 API 的功能,用户能看到明确的状态(已排队、待处理、稍后重试),并且当提供方恢复时能自动恢复。
大多数失败是可预见的,尽管它们何时发生不可预测。事先列出这些情况,你就能决定哪些要重试、哪些要停止、以及向用户展示什么。
常见类别:
并非所有错误都意味着同样的事情。瞬时问题通常值得重试,因为下一次调用可能成功(网络抖动、超时、502/503,以及在等待后的一些 429)。永久性问题通常不会自愈(无效凭证、错误的端点、格式错误的请求、权限拒绝)。
把所有错误一视同仁会把小事件变成停机。重试永久性失败浪费时间,更快触及速率限制,并积累会拖慢其他工作的积压。不重试瞬时失败则迫使用户重复操作并丢失本可以在片刻后完成的工作。
对那些暂停就像中断的工作流要特别关注:结账、登录、密码重置和通知(邮件/SMS/推送)。营销 API 的两秒延迟只是恼人,但支付授权的两秒延迟会阻塞收入。
一个有用的测试是:"这个调用现在必须完成用户的主要任务吗?" 如果是,你需要严格的超时、谨慎的重试和清晰的失败路径。如果不是,就把它移到队列中,让应用保持响应。
超时是你愿意等待的最长时间。没有明确的上限,一个缓慢的提供方会让等待的请求堆积并阻塞重要工作。
把等待分成两类会有帮助:
选择数值不是追求完美,而是要匹配人的耐心和你的工作流。
选择超时时间的实用方法是从体验反推:
权衡是真实的。超时太长会占用线程、工作进程和数据库连接;超时太短会产生虚假失败并触发不必要的重试。
当失败很可能是暂时的时,重试很有用:短暂的网络问题、DNS 抖动或一次性的 500/502/503。在这些情况下,再试一次可能成功,用户不会察觉。
风险在于重试风暴。当许多客户端同时失败并同时重试时,会压垮提供方(也可能压垮你自己的工作进程)。退避(backoff)和抖动(jitter)能防止这种情况。
重试预算能让你更审慎。限制尝试次数并限定总耗时,这样核心工作流就不会一直等待别人。
不要重试可预测的客户端错误,如 400/422 校验错误、401/403 认证问题或 404。这类错误几乎总是会再次失败,只会增加负载。
另一个防护措施:只有在有幂等性措施时才重试写操作(POST/PUT),否则会有重复扣款或重复记录的风险。
幂等性意味着多次执行同一请求,最终结果相同。这很重要,因为重试是常态:网络丢包、服务器重启、客户端超时都可能发生。没有幂等性,"有意"的重试会产生重复项并带来真实的金钱问题。
想象结账场景:支付 API 很慢,你的应用超时并重试。如果第一次调用其实已经成功,重试可能会产生第二次扣款。类似风险出现在创建订单、启动订阅、发送邮件/SMS、发起退款或创建支持单等操作中。
解决办法是为每个“执行操作”的调用附上幂等键(或请求 ID)。它应当针对用户动作唯一,而不是针对单次尝试。提供方(或你自己的服务)使用该键识别重复并返回相同的结果,而不是再次执行操作。
把幂等键当作数据模型的一部分,而不是一个可能被忘记的 header。
在用户开始动作(例如点击“支付”)时生成一个键,并把它存到本地记录中。
在每次尝试时:
如果你是内部调用的“提供方”,在服务器端也要强制执行相同行为。
断路器是一个安全开关。当外部服务开始失败时,你短时间内停止调用它,而不是继续堆积很可能会超时的请求。
断路器通常有三种状态:
当断路器打开时,你的应用应当有可预测的应对方式。如果地址校验 API 在注册时宕机,就接受地址并标记稍后审核。如果支付风控检查不可用,则把订单排队做人工审核或临时禁用该选项并进行说明。
选择与用户影响匹配的阈值:
把冷却期设短(几秒到一分钟),并限制半开时的探测。目标是先保护核心工作流,然后快速恢复。
当外部 API 变慢或宕机时,你的目标是让用户能继续进行。那就需要一个诚实的备用方案。
回退是 API 无法及时响应时应用的处理方式。选项包括使用缓存数据、切换到降级模式(隐藏非必需部件、禁用可选操作)、让用户手动输入以替代 API(手动填地址),或显示明确的下一步提示。
要诚实:不要在没有完成的情况下声称事情已完成。
如果工作不必在用户请求内完成,就把它推到队列并快速响应。常见候选项:发送邮件、同步到 CRM、生成报告、上报分析事件。
对核心操作要快速失败。如果某个 API 不必完成结账(或账户创建),就不要阻塞请求。接受订单、把外部调用放入队列并稍后对账。如果某个 API 是必需的(例如支付授权),就快速失败并给出清晰信息,而不是一直让用户等待。
用户看到的状态应当与后台发生的事情匹配:清晰的状态(完成、待处理、失败)、你能兑现的承诺(现在出收据,稍后确认)、可重试的方式以及 UI 中可见的记录(活动日志、待处理标识)。
速率限制是提供方告诉你的“你可以调用,但不要太频繁”。你会比想象中更早命中它:流量激增、后台作业同时触发,或错误导致循环重试。
从控制你产生多少请求开始。尽量批量处理,在安全的情况下缓存响应 30 到 60 秒,客户端侧节流以避免比提供方允许的更快突发。
收到 429 Too Many Requests 时,把它当作放慢节奏的信号。
Retry-After 时请遵守。还要限制并发度。单个工作流(如同步联系人)不应占用所有工作进程并挤占关键流程如登录或结账。使用独立池或按功能限额有帮助。
每个第三方调用都需要一个失败计划。你不需要完美,只需要在提供方糟糕时表现可预测。
决定如果调用现在失败会发生什么。结账时的税费计算可能是必须的;同步营销联系人通常可以等待。这个选择决定其余策略。
为不同类型调用选定超时并保持一致。然后设定重试预算,避免对慢速 API 不断猛击。
若请求会创建资源或收费,添加幂等键并保存请求记录。若支付请求超时,重试不应导致重复扣款。跟踪也有助于支持判断“是否已成功”。
当错误激增时,短时间停止调用提供方。对于必须同步的调用,展示明确的“重试”路径;对于可等待的调用,把工作入队稍后处理。
跟踪延迟、错误率和断路器的开/关事件。对持续性变化报警,而非单次短暂波动。
大多数 API 故障并非一开始就很严重。它们之所以变严重,是因为你的应用以最糟糕的方式反应:等待太久、重试过猛,并占用维持其他功能的相同工作进程。
这些模式会造成级联:
小修小补能避免大停机:仅重试可能短暂性的错误(超时、部分 429、部分 5xx),并用退避和抖动限制尝试次数;保持超时短且有目的;对任何会创建或收费的操作要求幂等性;并为部分故障设计降级策略。
在把集成推到生产前,用失败思维做一次快速检查。如果某项你无法回答“是”,就把它当作阻止核心工作流(如注册、结账或发送消息)发布的阻断项。
如果支付提供方开始超时,正确的行为是“结账页面仍能加载,用户看到明确信息,你不会无限等待”,而不是“所有东西都挂起直到超时”。
假设一个结账会调用三项服务:用于扣款的支付 API、计算税费的税务 API、以及发送收据的邮件 API。
支付调用是唯一必须同步的。税务或邮件的问题不应阻塞购买流程。
如果税务 API 有时需要 8 到 15 秒,结账若等待会导致用户放弃且占用工作进程。
更安全的流程:
结果:在税务提供方变慢时,弃单和卡住的订单减少。
收据邮件很重要,但绝不应阻塞支付捕获。如果邮件 API 失败,断路器在几次快速失败后应打开并在短冷却期内停止调用。
不要在请求中同步发送邮件,而是把“发送收据”的任务入队并附上幂等键(例如 order_id + email_type)。如果提供方宕机,队列会在后台重试,而用户仍看到购买成功。
结果:丢失确认邮件导致的支持工单减少,且非支付原因不会导致收入流失。
挑一个当它出问题最痛的工作流(结账、注册、开票),把它做成你的参考集成。然后把相同的默认值复制到其他地方。
一个简单的推广顺序:
把默认值写下来并保持一致:一个连接超时、一个请求超时、最大重试次数、退避范围、断路器冷却时间以及哪些错误可重试的规则。
在扩展到下一个工作流前做一次故障演练。在测试环境中强制超时(或屏蔽提供方),然后确认用户看到有用的信息、回退路径工作、并且队列重试不会无限堆积。
如果你要快速构建新产品,把这些可靠性默认值做成可复用的模板是值得的。对于使用 Koder.ai (koder.ai) 的团队,这通常意味着先定义超时、重试、幂等性和断路器规则,然后在生成和迭代新服务时复用相同的模式。