fix(sentry): Bind hub to lazy response streams#524
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #524 +/- ##
=======================================
Coverage 87.35% 87.35%
=======================================
Files 87 88 +1
Lines 14086 14103 +17
=======================================
+ Hits 12305 12320 +15
- Misses 1781 1783 +2
☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
| responses | ||
| .bind_hub(sentry::Hub::current()) | ||
| .into_multipart_response(rand::random()) |
There was a problem hiding this comment.
This is one of the two locations where we now bind the hub.
To expand on the description for why this has to be done here: We could technically import http_body and then pipe the size hint and other methods through from the underlying stream. Still, it means that we now add another box around every response, and we lose any form of optimization that axum might have on eager responses.
As long as we only have two places where we stream responses back, I think this is fine. Once we have more places, we'll have to reassess this.
Axum stream bodies are polled by hyper after the middleware stack unwinds, so Hub::current() inside a stream producer resolves to the tokio worker thread's ambient hub rather than the request's hub. Introduce SentryStream<S>, a pin-projected stream wrapper that re-activates a captured Arc<Hub> via HubSwitchGuard on every poll_next call, mirroring how SentryFuture works for futures. Bind the hub at stream construction time in the two affected endpoints: complete (multipart) and batch. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
550d425 to
acd434c
Compare
|
Moved back to draft as I prefer the alternative PR. |
When an axum handler returns a streaming body via
Body::from_stream(), theIntoResponseconversion runs inside the handler (within the sentry middleware), but the body's frames are polled by hyper after middleware has unwound. This meansHub::current()inside a stream producer resolves to whatever hub the tokio worker thread happens to have — not the request's hub.Three endpoints are affected:
object_get,complete(multipart), andbatch.We introduce
SentryStream<S>, a stream wrapper similar toSentryFuturein the Sentry SDK. It binds a provided hub to the stream.A blanket middleware approach was considered, but did not work: axum's
Bodyis type-erased, so there is no way to know whether it is a stream. Wrapping unconditionally through the middleware would strip thesize_hintfrom all buffered responses, causing hyper to fall back to chunked transfer encoding.This utility is a candidate for upstreaming into the sentry Rust SDK in a follow-up, alongside
SentryFutureandSentryFutureExt.Alternative to #526.