fix(core): retire finished spans without losing context - #9292
Conversation
Overall package sizeSelf size: 6.72 MB Dependency sizes| name | version | self size | total size | |------|---------|-----------|------------| | import-in-the-middle | 3.3.1 | 122.62 kB | 438.86 kB | | opentracing | 0.14.7 | 194.81 kB | 194.81 kB | | dc-polyfill | 0.1.11 | 25.74 kB | 25.74 kB |🤖 This report was automatically generated by heaviest-objects-in-the-universe |
🎉 All green!🧪 All tests passed 🎯 Code Coverage (details) 🔗 Commit SHA: 2dfaa24 | Docs | Datadog PR Page | Give us feedback! |
BenchmarksBenchmark execution time: 2026-07-14 00:28:16 Comparing candidate commit 2dfaa24 in PR branch Found 18 performance improvements and 0 performance regressions! Performance is the same for 2331 metrics, 63 unstable metrics.
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #9292 +/- ##
==========================================
+ Coverage 96.60% 96.61% +0.01%
==========================================
Files 919 920 +1
Lines 121692 122181 +489
Branches 21299 20921 -378
==========================================
+ Hits 117562 118049 +487
- Misses 4130 4132 +2
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
2a7ebf3 to
b861c04
Compare
Long-lived async resources can retain finished middleware spans and their parent chains after export, making retained heap grow with request count. The original span remains active until serialization and response listeners complete. Retained resources then keep a compact propagation facade, so late work preserves trace and baggage context without pinning the span graph. Fixes: #9227
Finished spans must remain live until trace serialization completes. Trace-level draining preserves that ordering without retirement work on every formatted span. The exporting-pipeline format benchmark improved from 1.367 s to 1.213 s on Node v24.18.0 / V8 13.6.233.17-node.50 (200k operations, 3 warmups, 7 runs).
Long-lived async resources retain finished middleware spans after trace erasure. Keep only the propagation state in the retired facade until late work requests a context, while preserving baggage and propagation metadata.
The BP Sirun converter rejects custom heap gauges during result conversion. Keep heap growth as a candidate-side threshold assertion and leave baseline runs available for built-in RSS comparisons.
The request-only control measured forced full GCs inside its timed window, making the benchmark report GC overhead as a default request regression. Keep forced GC for retained-resource heap checks, but measure ordinary request throughput and RSS without it.
b861c04 to
f75c4f7
Compare
Summary
Long-lived async resources can retain finished middleware spans and their parent chains after export, making retained heap grow with request count. This retires completed request stores to a compact propagation facade after serialization and response listeners complete.
Why
Nulling context at response finish breaks late work such as
res.end(); await work(). Keeping the original span preserves context but leaves the retention path intact. The facade preserves trace, baggage, log, and OTel propagation without retaining the original spans.Fixes: #9227