Skip to content

stats/otel: Add client side metrics for retries (A96) - #9317

Open
mbissa wants to merge 13 commits into
grpc:masterfrom
mbissa:implement-a96-retry-metrics
Open

stats/otel: Add client side metrics for retries (A96)#9317
mbissa wants to merge 13 commits into
grpc:masterfrom
mbissa:implement-a96-retry-metrics

Conversation

@mbissa

@mbissa mbissa commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

This PR implements retry metrics for A96

RELEASE NOTES:

  • stats/otel: Add client side metrics for retries as part of A96.

mbissa added 13 commits August 13, 2026 12:11
Fixed a race condition in pickfirst metrics tests where the assertions would
immediately poll the stats.TestMetricsRecorder. Depending on the goroutine
scheduling, asynchronous metrics like 'grpc.subchannel.open_connections'
would occasionally not be fully recorded before the test checked them,
causing flaky failures. This introduces an awaitMetric helper to wait for the
metrics to reach their expected values.
@mbissa mbissa added this to the 1.84 Release milestone Aug 13, 2026
@mbissa
mbissa requested a review from Pranjali-2501 August 13, 2026 08:58
@mbissa mbissa added the Type: Feature New features or improvements in behavior label Aug 13, 2026
@codecov

codecov Bot commented Aug 13, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.23810% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 83.27%. Comparing base (c841c90) to head (d991f3e).
⚠️ Report is 22 commits behind head on master.

Files with missing lines Patch % Lines
stats/opentelemetry/client_metrics.go 95.23% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #9317      +/-   ##
==========================================
+ Coverage   83.12%   83.27%   +0.14%     
==========================================
  Files         422      423       +1     
  Lines       35044    35180     +136     
==========================================
+ Hits        29131    29296     +165     
+ Misses       4410     4392      -18     
+ Partials     1503     1492      -11     
Files with missing lines Coverage Δ
stats/opentelemetry/opentelemetry.go 81.25% <ø> (+2.50%) ⬆️
stats/opentelemetry/client_metrics.go 89.50% <95.23%> (+1.64%) ⬆️

... and 50 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@mbissa

mbissa commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements OpenTelemetry client-side retry metrics, including retries, transparent retries, hedges, and retry delays, along with corresponding unit and end-to-end tests. The feedback highlights a potential race condition in client_metrics.go between the end of one attempt and the start of the next when calculating retry delays, suggesting the use of a mutex to protect these fields. Additionally, suggestions were made to update the expected attributes in the unit tests to include the grpc.status attribute.

Comment on lines +241 to +251
// Accumulate retry delay.
active := ci.activeAttempts.Add(1)
if active == 1 {
lastEndTime := ci.lastAttemptEndTime.Swap(0)
if lastEndTime > 0 {
delay := st.BeginTime.Sub(time.Unix(0, lastEndTime))
if delay > 0 {
ci.retryDelay.Add(int64(delay))
}
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

There is a potential race condition between the stats.End of attempt N (executed by the transport reader goroutine) and the stats.Begin of attempt N+1 (executed by the client-call goroutine).

If stats.Begin of the next attempt runs and increments activeAttempts before stats.End of the previous attempt has finished storing lastAttemptEndTime, the next attempt will swap lastAttemptEndTime and get 0 (or an older value), missing the retry delay calculation. Then, the previous attempt's stats.End will store its end time after the swap, corrupting the state for subsequent attempts.

Consider protecting these retry tracking fields with a sync.Mutex in callInfo to ensure thread-safe state transitions across different goroutines.

Data: metricdata.Histogram[int64]{
DataPoints: []metricdata.HistogramDataPoint[int64]{
{
Attributes: attribute.NewSet(attribute.String("grpc.method", "test-method"), attribute.String("grpc.target", "test-target")),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Update the expected attributes to include grpc.status with value "OK" to match the updated retry metrics implementation.

Suggested change
Attributes: attribute.NewSet(attribute.String("grpc.method", "test-method"), attribute.String("grpc.target", "test-target")),
Attributes: attribute.NewSet(attribute.String("grpc.method", "test-method"), attribute.String("grpc.target", "test-target"), attribute.String("grpc.status", "OK")),

Data: metricdata.Histogram[int64]{
DataPoints: []metricdata.HistogramDataPoint[int64]{
{
Attributes: attribute.NewSet(attribute.String("grpc.method", "test-method"), attribute.String("grpc.target", "test-target")),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Update the expected attributes to include grpc.status with value "OK" to match the updated retry metrics implementation.

Suggested change
Attributes: attribute.NewSet(attribute.String("grpc.method", "test-method"), attribute.String("grpc.target", "test-target")),
Attributes: attribute.NewSet(attribute.String("grpc.method", "test-method"), attribute.String("grpc.target", "test-target"), attribute.String("grpc.status", "OK")),

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Type: Feature New features or improvements in behavior

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants