Repository navigation
Issue 8831 exporter backpressure - #8928
codedbyadiiii wants to merge 11 commits into
Conversation
|
Pull request dashboard statusWaiting on the author · refreshed 2026-10-23 16:51 UTC Two things need attention:
Status above doesn't look right?
|
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #8928 +/- ##
============================================
- Coverage 90.41% 90.31% -0.11%
- Complexity 10981 10993 +12
============================================
Files 1019 1019
Lines 30016 30189 +173
Branches 3917 3942 +25
============================================
+ Hits 27140 27266 +126
- Misses 1923 1961 +38
- Partials 953 962 +9 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
jkwatson
left a comment
There was a problem hiding this comment.
I'm ok with the API changes if Jack is.
Signed-off-by: Aditya_Nalge <adityanalge1234@gmail.com>
jack-berg
left a comment
There was a problem hiding this comment.
Before reviewing the code details, I want to align on overall architecture.
There's a key alternative design to the one suggested here, which is to add a boolean supportsExportBackpressure() (or equivalent name).
The idea with this is method is that it defaults to false, and if true, then processors change their behavior to continue the processing loop as soon as export(Collection<data>) synchronously returns, rather than waiting for the CompletableResultCode future to complete.
Exporters become responsible for understanding the state of their own worker queues, and signaling backpressure to callers by blocking export(Collect<data>) when at capacity.
For the purposes of discussion, I'll call the implementation in this PR "integer limit, processor controlled", and I'll call the idea I proposed above "boolean, exporter controlled". Here's a comparison of the two implementations:
| Concern | Integer limit, processor controlled | boolean, exporter controlled |
|---|---|---|
| Responsibility | Exporter advertises capacity. Each processor enforces it. | Exporter owns both capacity and enforcement. |
| Shared resources | Independent processors can collectively exceed the advertised limit. | Exporter can enforce one budget across callers. Shared transports still require coordination. |
| Dynamic capacity | A fixed count is simple but cannot express changing capacity or byte-based limits. | Can adapt admission to actual resource availability. |
| Blocking | Processor owns the capacity wait and can arrange to service lifecycle requests while waiting. | Exporter owns the capacity wait. The submitting worker cannot service lifecycle requests during admission, but a timeout overload can bound that delay if honored. |
| Timeouts | Processor can enforce its own capacity-wait deadline and use the remaining budget to await completion. | An export() timeout overload can bound admission, with the processor subtracting elapsed admission time before awaiting completion. This requires an explicit cooperative timeout contract. |
| Implementation burden | Admission bookkeeping in each processor. Exporters mostly just advertise a number. | Admission bookkeeping in each exporter or shared sender. Processors still track results for flush/shutdown. Neither model inherently requires an additional thread pool. |
| Composition | Minimum child limit is a conservative composite limit, potentially underutilizing faster children. | Children enforce their own limits, but a blocked child can delay submission to other children. |
| Uncooperative exporters | An exporter can still block inside export() indefinitely, regardless of its advertised limit. |
An exporter can ignore its admission timeout and block indefinitely. This is an existing processor vulnerability, not unique to exporter-controlled admission. |
Thanks, this distinction is helpful. I agree that exporter-controlled backpressure is more flexible, especially for shared exporters and dynamic or byte-based capacity. My main concern is defining the timeout overload as a clear cooperative contract and ensuring exporter admission cannot indefinitely delay processor lifecycle operations. I’ll rework the proposal around supportsExportBackpressure() and account for those constraints before we get into implementation details. |
Processors don't actually have any protection against exporters indefinitely delaying today so I'm not fully convinced we need a new export w/ timeout overload.
Let's wait to here from @jkwatson and/or @trask before reworking the code, since its possible the consensus is to stick with the integer limit approach. |
Sounds good. I’ll hold off on further architecture changes and wait for input from @jkwatson and/or @trask. The CI test assertion is fixed separately. |
|
no strong opinion from me on which approach. |
|
Pushed 768fc85 to fix the remaining PR-specific CI failure.
The On the architecture question, I will hold off on reworking the implementation pending input from @trask, as suggested. |
|
The updated CI run confirms the exporter assertion fix: all platform/JDK builds passed except macOS Java 8. That job failed in the existing |
Resolves #8831
Summary
Adds an opt-in mechanism for exporters to signal their supported export concurrency.
Changes
getConcurrencyLimit()to span, log, and metric exporter interfaces.BatchSpanProcessorBatchLogRecordProcessorPeriodicMetricReaderTesting
./gradlew :sdk:trace:test :sdk:logs:test :sdk:metrics:test./gradlew :sdk:trace:jApiCmp :sdk:logs:jApiCmp :sdk:metrics:jApiCmp