← 中文资源

简体中文版本

在依赖边界注入超时

让下游调用可控地挂起,断言超时路径返回 504、取消请求并释放资源,而不是拖垮整个进程。

阅读英文原文

概述

Node 的 fetch 默认没有请求超时。依赖方接受连接后一直不响应,请求会一直挂到套接字层放弃,可能是几分钟。这段时间里 worker 被占用、数据库连接被借出,客户端多半已经重试。一个慢依赖就此演变为自我造成的故障,因为没有任何机制限制等待时间。

步骤

  1. 每个出站请求都传入基于依赖延迟预算的显式超时:
const res = await fetch(url, { signal: AbortSignal.timeout(2000) });
  1. 把 TimeoutError / AbortError 映射为 504,并对非幂等操作标记为不可重试。
  2. 用 Toxiproxy 注入确定性的延迟:
toxiproxy-cli create payment -l 127.0.0.1:8666 -u payment-provider:443
toxiproxy-cli toxic add payment -t latency -a latency=5000
  1. 断言响应时间小于 3 秒,并检查 pool.totalCount === pool.idleCount,确认没有连接被占用。
  2. 移除 toxic,确认下一次请求无需重启即可恢复。

验证

注入 5 秒延迟后,结账接口应在约 2 秒返回 504,响应体包含 retryable: false。请求结束后连接池应全部空闲;移除延迟后同一接口立即返回 200。重复执行多次结果一致,说明测试不依赖真实网络抖动。

注意事项

  • 客户端超时不会取消上游已经接受的业务处理,超时属于“结果未知”而非失败。
  • 网络层超时与应用层超时是两层,需保持一致,避免代理比客户端等待更久。
  • 对支付等非幂等操作,超时后盲目重试会造成重复扣款,应配合幂等键核对。
  • Toxiproxy 自身增加了一跳网络,需要在真实环境中确认延迟数值。
  • 超时后若连接或定时器未释放,下一次故障会表现为连接池耗尽而不是响应变慢。