ref: Flush trace buckets when segment spans finish - #7170
Conversation
Codecov Results 📊✅ 105016 passed | ⏭️ 6677 skipped | Total: 111693 | Pass Rate: 94.02% | Execution Time: 367m 48s 📊 Comparison with Base Branch
All tests are passing successfully. ✅ Patch coverage is 100.00%. Project has 2484 uncovered lines. Coverage diff@@ Coverage Diff @@
## main #PR +/-##
==========================================
+ Coverage 90.15% 90.15% —%
==========================================
Files 193 193 —
Lines 25215 25215 —
Branches 9224 9224 —
==========================================
+ Hits 22730 22731 +1
- Misses 2485 2484 -1
- Partials 1433 1431 -2Generated by Codecov Action |
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.
Reviewed by Cursor Bugbot for commit 54334a3. Configure here.
| The span batcher flushes pending items asynchronously with the main thread. | ||
| Flushes triggered by segments finishing are asynchronous, and can collect buckets | ||
| that would have otherwise been flushed synchronously by `sentry_sdk.flush()`. |
There was a problem hiding this comment.
I'm finding this comment a little tricky to follow. My understanding of this section is:
- The span batcher sends out pending items in the background, separately from the main thread.
- When a segment finishes, that triggers a background flush too
- The background flush in point 2 can end up sending buckets that sentry_sdk.flush() would otherwise have sent immediately.
Do I have this right? And why is point 3 problematic? Is it because we need those buckets immediately when invoking sentry_sdk.flush() and we may not get them because those buckets are in the process of being flushed by the background process?
There was a problem hiding this comment.
Yes that's correct! To add some links:
Each batcher has a flushing thread that runs the _flush_loop() method.
When a segment span finishes, _flush() is triggered inside the thread here:
sentry-python/sentry_sdk/_span_batcher.py
Line 94 in 4e4ea83
This is what I called "asynchronous" in the comment.
When you call sentry_sdk.flush(), it triggers the flush here
sentry-python/sentry_sdk/client.py
Line 1381 in 4e4ea83
which is not in the flushing thread. This runs synchronously with the user code.

Description
Mark the corresponding bucket as pending in the span buffer when a segment span is added.
This aims to keep memory pressure low. Segment spans typically finish after their children. There may be multiple segments in a trace, and flushing more frequently leads to more outbound network requests in these cases.
Adapt span batcher tests by adding an outer segment in most tests. As a result, the various flush conditions are still exercised as the assertions run before the segment span has finished (finishing the segment span otherwise flushes the buffer as well).
The tests that exercise multiple buckets are changed to use
traces.new_trace()in combination with a segment span that's left openWithout changes to the
sentry_initfixture, tests fail on free-threading. This is because the background flusher collects pending items beforesentry_sdk.flush()can synchronously flush all everything. The background flush is asynchronous and creates a race conditions.Issues
Reminders
uv run ruff.feat:,fix:,ref:,meta:)