Rust in Everything
基于 tower-http 0.7.1

结局

一个请求怎么算结束?「返回了响应」远远不够:响应可能是 500,可能是带着 grpc-status: 13 的 200;body 可能读完了,可能读到一半出错,也可能读了一半就被调用方丢掉。tower-http 把这件事拆成三个问题,分给不同的模块:

  1. classify:什么算失败:MakeClassifier → ClassifyResponse → ClassifyEos 三个 trait,看完响应头就下结论(Ready)或者等 trailers(RequiresEos);四个内置分类器;gRPC 分类器眼里 HTTP 500 不算失败;这个模块不受 feature 控制,crate 里只有 trace 在用。
  2. Trace 的内部:8 个类型参数;什么算结束(None、trailers、is_end_stream);body 出错算不算失败取决于分类器;延迟用的是标准库时钟;0.7.0 把默认事件显式挂到请求 span 上。
  3. CatchPanic:两次 catch_unwind,一次包同步的 call、一次包响应 future;panic 信息只认 String 和 &str;响应 body 一律擦成 UnsyncBoxBody。
  4. InFlightRequests:在途计数:计数守卫从 future 移进 body,body 被 drop 才减一,读完但没丢也算在途;SSE 一直算在途;run_emitter 定期上报。
  5. 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 不知道响应算不算失败。要回答全部三个问题,就得把几个层叠在一起,而它们的相对顺序决定各自看到什么。

💬 关联讨论

发起讨论
加载中...