Repository navigation
fix(browser): Apply Http timing attributes to streamed http.client spans - #19643
Conversation
size-limit report 📦
|
node-overhead report 🧳Note: This is a synthetic benchmark with a minimal express app and does not necessarily reflect the real-world performance impact in an application.
|
c28083a to
06bccc6
Compare
bfee1f9 to
6b0eb4f
Compare
| client.on('afterSegmentSpanEnd', segmentSpan => buffer.flush(segmentSpan.spanContext().traceId)); | ||
| client.on('afterSegmentSpanEnd', segmentSpan => { | ||
| const traceId = segmentSpan.spanContext().traceId; | ||
| setTimeout(() => { |
There was a problem hiding this comment.
q/l: Should we wrap this in our safeUnref function? Or is this guaranteed to run only on the browser?
There was a problem hiding this comment.
it's guaranteed to only run in the browser. There will be a dedicated server-side spanStreamingIntegration which doesn't need this logic
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
| gzip: false, | ||
| brotli: false, | ||
| limit: '129 KB', | ||
| limit: '130 KB', |
There was a problem hiding this comment.
Browser bundle size increase flagged per project rules
Low Severity
The CDN Bundle (incl. Tracing) uncompressed size limit increased from 129 KB to 130 KB (~0.8% increase). Per the project rules, large bundle size increases in browser packages need to be flagged even when unavoidable. The PR description acknowledges this trade-off for adding HTTP timing support to streamed spans.
Triggered by project rule: PR Review Guidelines for Cursor Bot
…spans (#19643) This PR fixes a temporary bug in span streaming where we didn't add Http timing attributes (see #19613). We can fix this by following OTels approach: - delay the ending of `http.client` spans until either 300ms pass by or we receive the PerformanceResourceTiming entry with the respective timing information. Of course we end the span with the original timestamp then. - Unfortunately, we can only do this for streamed span because transaction-based spans cannot stay open longer than their parent (e.g. a pageload or navigation). Otherwise they'd get dropped. So we have to differentiate between the two modes here (RIP bundle size 😢) - To ensure we don't flush unnecessarily often, we also now delay flushing the span buffer for 500ms after a segment span ends. This slightly changed test semantics in a few integration tests because manually consecutively segments are now also sent in one envelope. This is completely fine (actually preferred) because we flush less often (i.e. fewer requests). closes #19613
…spans (#19643) This PR fixes a temporary bug in span streaming where we didn't add Http timing attributes (see #19613). We can fix this by following OTels approach: - delay the ending of `http.client` spans until either 300ms pass by or we receive the PerformanceResourceTiming entry with the respective timing information. Of course we end the span with the original timestamp then. - Unfortunately, we can only do this for streamed span because transaction-based spans cannot stay open longer than their parent (e.g. a pageload or navigation). Otherwise they'd get dropped. So we have to differentiate between the two modes here (RIP bundle size 😢) - To ensure we don't flush unnecessarily often, we also now delay flushing the span buffer for 500ms after a segment span ends. This slightly changed test semantics in a few integration tests because manually consecutively segments are now also sent in one envelope. This is completely fine (actually preferred) because we flush less often (i.e. fewer requests). closes #19613
…spans (#19643) This PR fixes a temporary bug in span streaming where we didn't add Http timing attributes (see #19613). We can fix this by following OTels approach: - delay the ending of `http.client` spans until either 300ms pass by or we receive the PerformanceResourceTiming entry with the respective timing information. Of course we end the span with the original timestamp then. - Unfortunately, we can only do this for streamed span because transaction-based spans cannot stay open longer than their parent (e.g. a pageload or navigation). Otherwise they'd get dropped. So we have to differentiate between the two modes here (RIP bundle size 😢) - To ensure we don't flush unnecessarily often, we also now delay flushing the span buffer for 500ms after a segment span ends. This slightly changed test semantics in a few integration tests because manually consecutively segments are now also sent in one envelope. This is completely fine (actually preferred) because we flush less often (i.e. fewer requests). closes #19613
…spans (#19643) This PR fixes a temporary bug in span streaming where we didn't add Http timing attributes (see #19613). We can fix this by following OTels approach: - delay the ending of `http.client` spans until either 300ms pass by or we receive the PerformanceResourceTiming entry with the respective timing information. Of course we end the span with the original timestamp then. - Unfortunately, we can only do this for streamed span because transaction-based spans cannot stay open longer than their parent (e.g. a pageload or navigation). Otherwise they'd get dropped. So we have to differentiate between the two modes here (RIP bundle size 😢) - To ensure we don't flush unnecessarily often, we also now delay flushing the span buffer for 500ms after a segment span ends. This slightly changed test semantics in a few integration tests because manually consecutively segments are now also sent in one envelope. This is completely fine (actually preferred) because we flush less often (i.e. fewer requests). closes #19613
…spans (#19643) This PR fixes a temporary bug in span streaming where we didn't add Http timing attributes (see #19613). We can fix this by following OTels approach: - delay the ending of `http.client` spans until either 300ms pass by or we receive the PerformanceResourceTiming entry with the respective timing information. Of course we end the span with the original timestamp then. - Unfortunately, we can only do this for streamed span because transaction-based spans cannot stay open longer than their parent (e.g. a pageload or navigation). Otherwise they'd get dropped. So we have to differentiate between the two modes here (RIP bundle size 😢) - To ensure we don't flush unnecessarily often, we also now delay flushing the span buffer for 500ms after a segment span ends. This slightly changed test semantics in a few integration tests because manually consecutively segments are now also sent in one envelope. This is completely fine (actually preferred) because we flush less often (i.e. fewer requests). closes #19613
…spans (#19643) This PR fixes a temporary bug in span streaming where we didn't add Http timing attributes (see #19613). We can fix this by following OTels approach: - delay the ending of `http.client` spans until either 300ms pass by or we receive the PerformanceResourceTiming entry with the respective timing information. Of course we end the span with the original timestamp then. - Unfortunately, we can only do this for streamed span because transaction-based spans cannot stay open longer than their parent (e.g. a pageload or navigation). Otherwise they'd get dropped. So we have to differentiate between the two modes here (RIP bundle size 😢) - To ensure we don't flush unnecessarily often, we also now delay flushing the span buffer for 500ms after a segment span ends. This slightly changed test semantics in a few integration tests because manually consecutively segments are now also sent in one envelope. This is completely fine (actually preferred) because we flush less often (i.e. fewer requests). closes #19613
…spans (#19643) This PR fixes a temporary bug in span streaming where we didn't add Http timing attributes (see #19613). We can fix this by following OTels approach: - delay the ending of `http.client` spans until either 300ms pass by or we receive the PerformanceResourceTiming entry with the respective timing information. Of course we end the span with the original timestamp then. - Unfortunately, we can only do this for streamed span because transaction-based spans cannot stay open longer than their parent (e.g. a pageload or navigation). Otherwise they'd get dropped. So we have to differentiate between the two modes here (RIP bundle size 😢) - To ensure we don't flush unnecessarily often, we also now delay flushing the span buffer for 500ms after a segment span ends. This slightly changed test semantics in a few integration tests because manually consecutively segments are now also sent in one envelope. This is completely fine (actually preferred) because we flush less often (i.e. fewer requests). closes #19613
…spans (#19643) This PR fixes a temporary bug in span streaming where we didn't add Http timing attributes (see #19613). We can fix this by following OTels approach: - delay the ending of `http.client` spans until either 300ms pass by or we receive the PerformanceResourceTiming entry with the respective timing information. Of course we end the span with the original timestamp then. - Unfortunately, we can only do this for streamed span because transaction-based spans cannot stay open longer than their parent (e.g. a pageload or navigation). Otherwise they'd get dropped. So we have to differentiate between the two modes here (RIP bundle size 😢) - To ensure we don't flush unnecessarily often, we also now delay flushing the span buffer for 500ms after a segment span ends. This slightly changed test semantics in a few integration tests because manually consecutively segments are now also sent in one envelope. This is completely fine (actually preferred) because we flush less often (i.e. fewer requests). closes #19613
…spans (#19643) This PR fixes a temporary bug in span streaming where we didn't add Http timing attributes (see #19613). We can fix this by following OTels approach: - delay the ending of `http.client` spans until either 300ms pass by or we receive the PerformanceResourceTiming entry with the respective timing information. Of course we end the span with the original timestamp then. - Unfortunately, we can only do this for streamed span because transaction-based spans cannot stay open longer than their parent (e.g. a pageload or navigation). Otherwise they'd get dropped. So we have to differentiate between the two modes here (RIP bundle size 😢) - To ensure we don't flush unnecessarily often, we also now delay flushing the span buffer for 500ms after a segment span ends. This slightly changed test semantics in a few integration tests because manually consecutively segments are now also sent in one envelope. This is completely fine (actually preferred) because we flush less often (i.e. fewer requests). closes #19613
…spans (#19643) This PR fixes a temporary bug in span streaming where we didn't add Http timing attributes (see #19613). We can fix this by following OTels approach: - delay the ending of `http.client` spans until either 300ms pass by or we receive the PerformanceResourceTiming entry with the respective timing information. Of course we end the span with the original timestamp then. - Unfortunately, we can only do this for streamed span because transaction-based spans cannot stay open longer than their parent (e.g. a pageload or navigation). Otherwise they'd get dropped. So we have to differentiate between the two modes here (RIP bundle size 😢) - To ensure we don't flush unnecessarily often, we also now delay flushing the span buffer for 500ms after a segment span ends. This slightly changed test semantics in a few integration tests because manually consecutively segments are now also sent in one envelope. This is completely fine (actually preferred) because we flush less often (i.e. fewer requests). closes #19613
…segment-end flush timer (#25490) Since span streaming became the default (#22642) and segment-end flushing turned on for server runtimes (#23714), every root span end schedules `setTimeout(flush, 500)`, sampled or not. #23714 relies on `safeUnref` to stop that timer holding a server open, but workerd timers have no `unref()`. A Durable Object invocation stays open until its pending timers fire, so every instrumented DO `fetch`, alarm, `webSocketMessage` and propagated RPC call runs about 500 ms longer. That time is billed as duration, and the pending timer also blocks hibernation. This happens at `tracesSampleRate: 0` too. The 500 ms delay comes from the browser (#19643): `http.client` spans stay open up to 300 ms waiting for resource timing, so they can end after their segment. Neither that nor the buffer-memory reason for flushing at segment end on servers (#23714) applies to Workers, where nothing waits for resource timing and spans are flushed at the end of every invocation. The Cloudflare client now registers `spanStreamingIntegration({ flushOnSegmentEnd: false })` unless the user supplies their own. The runtime doesn't need the timer: the boundary flush in `wrapMethodWithSentry` runs after the method span ends, and the cached client's eager drain covers spans that end after the flush point. This matches the existing `_flushInterval: 0` for the log and metric buffers. Plain Worker handlers lose the timer too: it doesn't hold their requests open, so it cost them nothing, but `withSentry`'s boundary flush already delivers their spans. In workerd, with the same change applied to 11.6.0, DO `fetch` and alarm wall time drops from about 505 ms to about 6 ms, and at `tracesSampleRate: 1.0` the same span envelopes still arrive. Fixes #25489 Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>


This PR fixes a temporary bug in span streaming where we didn't add Http timing attributes (see #19613). We can fix this by following OTels approach:
http.clientspans until either 300ms pass by or we receive the PerformanceResourceTiming entry with the respective timing information. Of course we end the span with the original timestamp then.closes #19613