结局
一个请求怎么算结束?「返回了响应」远远不够:响应可能是 500,可能是带着 grpc-status: 13 的 200;body 可能读完了,可能读到一半出错,也可能读了一半就被调用方丢掉。tower-http 把这件事拆成三个问题,分给不同的模块:
- classify:什么算失败:
MakeClassifier→ClassifyResponse→ClassifyEos三个 trait,看完响应头就下结论(Ready)或者等 trailers(RequiresEos);四个内置分类器;gRPC 分类器眼里 HTTP 500 不算失败;这个模块不受 feature 控制,crate 里只有trace在用。 - Trace 的内部:8 个类型参数;什么算结束(
None、trailers、is_end_stream);body 出错算不算失败取决于分类器;延迟用的是标准库时钟;0.7.0 把默认事件显式挂到请求 span 上。 - CatchPanic:两次
catch_unwind,一次包同步的call、一次包响应 future;panic 信息只认String和&str;响应 body 一律擦成UnsyncBoxBody。 - InFlightRequests:在途计数:计数守卫从 future 移进 body,body 被 drop 才减一,读完但没丢也算在途;SSE 一直算在途;
run_emitter定期上报。 - OnEarlyDrop:请求被放弃:future 没出响应就被丢、body 没到结尾就被丢,两种事件;回调是工厂;桥到
trace::OnFailure时要放在TraceLayer里面才挂得上请求 span。
flowchart TB
resp[响应] --> fail{失败了吗}
fail --> cls[classify]
resp --> done{结束了吗}
done --> tr[Trace 的 ResponseBody]
resp --> gone{被放弃了吗}
gone --> inf[InFlightRequests]
gone --> oed[OnEarlyDrop]
panic[handler panic] --> cp[CatchPanic:变成 500]
cp --> resp
三个问题互不依赖:classify 不知道 body 有没有读完,Trace 不知道 future 有没有被丢,OnEarlyDrop 不知道响应算不算失败。要回答全部三个问题,就得把几个层叠在一起,而它们的相对顺序决定各自看到什么。
💬 关联讨论
发起讨论加载中...