[v2] fix: implement single-call enforcement for Span.Finish#3334
Conversation
Datadog ReportBranch report: ✅ 0 Failed, 4474 Passed, 66 Skipped, 27m 14.85s Total Time |
BenchmarksBenchmark execution time: 2025-03-25 18:27:02 Comparing candidate commit 179f955 in PR branch Found 2 performance improvements and 0 performance regressions! Performance is the same for 54 metrics, 0 unstable metrics. scenario:BenchmarkSetTagString-24
scenario:BenchmarkSetTagStringer-24
|
|
|
||
| pprofCtxActive context.Context `msg:"-"` // contains pprof.WithLabel labels to tell the profiler more about this span | ||
| pprofCtxRestore context.Context `msg:"-"` // contains pprof.WithLabel labels of the parent span (if any) that need to be restored when this span finishes | ||
| sentinel atomic.Uint32 `msg:"-"` // sentinel value to detect if Span.Finish has been called to only finish the span once |
There was a problem hiding this comment.
I wonder if we can do better with the naming? Or maybe we can add more explanation.
There was a problem hiding this comment.
agree with this, could this be called finished instead?
There was a problem hiding this comment.
I changed it to finishGuard.
Updated the testAsyncSpanRace function to better simulate concurrent Finish calls on spans. Introduced a WaitGroup to synchronize concurrent finishes and ensure proper execution order, addressing potential data races during testing.
|
I am not sure if this is a complete fix. Everything in Why didn't we consider acquiring the |
|
@felixge The guard should be enough. It's an atomic value. Two concurrent calls to Regarding considering acquiring the |
The guard is only enough for the double Finish issue. It's not enough for a |
|
You’re right to raise this concern. We worked on this together with @darccio and evaluated a few different approaches. In the end, we opted to keep the changes minimal and targeted to avoid introducing broader side effects. That said, we agree this isn’t a complete fix. The current implementation does have inconsistencies around locking, especially in how nested functions operate on shared state. It’s becoming increasingly difficult to track which paths require We should prioritize a deeper audit of the span code—especially |
What does this PR do?
This PR adds a sentinel value to ensure that calling
Finishon any given span will only trigger the finishing flow once.Motivation
A potential source of data races is when a user misuses the tracer, as finishing the same span multiple times by calling
Finishmore than once, concurrently or serially in a tight loop.Reviewer's Checklist
v2-devbranch and reviewed by @DataDog/apm-go.Unsure? Have a question? Request a review!