Skip to content

feat(Spanner.V1): Add attempt metrics for streams - #15806

Open
robertvoinescu-work wants to merge 1 commit into
googleapis:mainfrom
robertvoinescu-work:spanner/builtInMetricsStream
Open

robertvoinescu-work wants to merge 1 commit into
googleapis:mainfrom
robertvoinescu-work:spanner/builtInMetricsStream

Conversation

@robertvoinescu-work

@robertvoinescu-work robertvoinescu-work commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

b/404948213

@product-auto-label product-auto-label Bot added the api: spanner Issues related to the Spanner API. label Aug 7, 2026
@robertvoinescu-work
robertvoinescu-work force-pushed the spanner/builtInMetricsStream branch from 0af58c5 to 8178bef Compare August 7, 2026 05:15
gemini-code-assist[bot]

This comment was marked as outdated.

@robertvoinescu-work
robertvoinescu-work force-pushed the spanner/builtInMetricsStream branch 9 times, most recently from 0f81d4d to 57ee54c Compare August 11, 2026 20:44
@robertvoinescu-work
robertvoinescu-work force-pushed the spanner/builtInMetricsStream branch 4 times, most recently from c9920b4 to 0db1a35 Compare August 28, 2026 19:18
@robertvoinescu-work robertvoinescu-work changed the title feat(Spanner.V1): Add StreamTracer for streaming RPC built-in metrics feat(Spanner.V1): Add built in metrics for streams Aug 31, 2026
@robertvoinescu-work
robertvoinescu-work force-pushed the spanner/builtInMetricsStream branch 5 times, most recently from c341414 to ac638b6 Compare September 15, 2026 21:58
@robertvoinescu-work robertvoinescu-work changed the title feat(Spanner.V1): Add built in metrics for streams feat(Spanner.V1): Add attempt metrics for streams Sep 15, 2026
@robertvoinescu-work

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 built-in metrics instrumentation for server streaming calls in the Spanner client, introducing InstrumentedAsyncStreamReader to track stream duration and completion status, along with corresponding unit tests. Feedback on the changes highlights a critical resource leak where the original AsyncServerStreamingCall is not disposed, thread-safety concerns in InstrumentedAsyncStreamReader that should be resolved using Interlocked operations, and a minor typo in the test comments.

@robertvoinescu-work
robertvoinescu-work force-pushed the spanner/builtInMetricsStream branch from ac638b6 to d5d12d6 Compare September 15, 2026 22:46
@robertvoinescu-work

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 built-in metrics instrumentation for Spanner server streaming calls by introducing InstrumentedAsyncStreamReader and updating MetricsInterceptor to intercept AsyncServerStreamingCall. It also consolidates test doubles and adds comprehensive streaming tests. A critical issue was identified where disposing of an early-terminated AsyncServerStreamingCall fails to dispose of the InstrumentedAsyncStreamReader, resulting in lost attempt metrics; wrapping the dispose action to dispose of the instrumented reader first was suggested.

@robertvoinescu-work
robertvoinescu-work force-pushed the spanner/builtInMetricsStream branch from d5d12d6 to 11af836 Compare September 15, 2026 22:55
@robertvoinescu-work

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 adds built-in metrics instrumentation for gRPC server streaming calls in the Google Cloud Spanner V1 client, introducing InstrumentedAsyncStreamReader to track stream duration and completion status, and updating MetricsInterceptor to intercept streaming calls. It also includes comprehensive unit tests. The feedback suggests ensuring robust resource cleanup during disposal by using a try-finally block, mapping OperationCanceledException to StatusCode.Cancelled instead of StatusCode.Unknown for more accurate cancellation metrics (along with updating the tests), and fixing a minor typo in a comment.

@robertvoinescu-work
robertvoinescu-work force-pushed the spanner/builtInMetricsStream branch from 11af836 to 3bed32f Compare September 15, 2026 23:25
@robertvoinescu-work
robertvoinescu-work marked this pull request as ready for review September 15, 2026 23:28
@robertvoinescu-work
robertvoinescu-work requested a review from a team as a code owner September 15, 2026 23:28

var instrumentedStreamReader = new InstrumentedAsyncStreamReader<TResponse>(
call.ResponseStream,
stopwatch,

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.

So the amount of time we measure is how long it takes to read the whole stream? Are you sure that's what we are meant to do here?

var labels = Labeler.GetLabels(context.Method.Name, dbNameProvider, status, _clientIdentity);
RecordAttemptMetrics(elapsedMs, labels);

// Fire and forget, unlike the unary path: this callback runs inline on the reader's MoveNext

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.

MoveNext here is async. Why can't this be awaited there?

/// <summary>
/// Invokes the close callback, unless the stream has already closed.
/// </summary>
private void TryRecordClose(StatusCode status)

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.

nit: Or something of the sort? Instead of closed?

Suggested change
private void TryRecordClose(StatusCode status)
private void Done(StatusCode status)

/// <summary>
/// Records the close of the stream when the consumer abandons it before completion.
/// </summary>
public void NotifyClosed()

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.

Shouldn't this be Dispose?

But also, from when a user abandons the stream to when it's Disposed of, there might be a long time. Are we sure we want to record that?

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

Labels

api: spanner Issues related to the Spanner API.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants