分阶段超时与代理请求的总截止时间
将各阶段的限制与经由代理的整项操作的总时间预算区分开来,包括重试和响应读取。
连接超时和读取超时只限制某些特定的等待,并不一定限制整项经由代理的操作;这项操作还可能包括排队等待、DNS、CONNECT、TLS、重定向、重试以及读取响应。
| 限制 | 范围 |
|---|---|
| 连接超时 | 按客户端定义建立连接 |
| 读取无进展超时 | 在没有预期数据进展的情况下等待 |
| 总截止时间 | 整项操作允许的持续时间 |
从操作的预算开始
在可用时,使用客户端有文档说明的总截止时间或取消机制,并配合各阶段的限制。HTTPX 将连接池、连接、读取和写入的等待分开处理。Requests 说明其超时并不是完整下载的限制。curl 提供总传输超时。
例如,一项二十秒的任务在排队上花两秒、建立路由花三秒、一次不成功的交换花六秒,那么下一次尝试大约只剩九秒。若给每次重试都重新分配二十秒,就会丢弃最初的预算。
用单调时钟来计量已经过去的时间。把绝对截止时间或剩余时长沿拥有该工作的各层传递。如果外部的取消机制无法强制所需范围,就要把这一限制明确说明。
把响应体和清理也算进去
在响应头之后返回的方法可能把响应体的读取留在其截止时间之外。要判断预算覆盖的是建立阶段、一次完整的有限下载,还是带有独立存活规则的长连接流。现代 .NET 中用一个令牌贯穿响应头和响应体取消的示例会在两个阶段之间传递同一个令牌。
在下一次尝试占用连接池容量之前,要留出关闭响应并完成取消的时间。记录失败的阶段和已经过去的时间;反复读取虽有进展,却可能满足无进展限制,而整项工作耗时过长。
网关面向上游的截止时间属于该网关。一旦它返回 504,客户端尚未使用的预算也无法延长已经结束的尝试。在判断需要修正哪项设置时,要让每个计时器始终归属于它的所有者。