feat(spanner): add client-level CallContextConfigurator to SpannerOptions - #14256
Conversation
…ions
Adds support for configuring a client-wide CallContextConfigurator via
SpannerOptions.Builder#setCallContextConfigurator.
This allows applications (such as async and reactive pipelines where
operations span across multiple executor threads) to customize gRPC
options, timeouts, and headers across all RPCs without relying on
thread-local io.grpc.Context propagation.
Key changes:
- SpannerOptions: Added setCallContextConfigurator/getCallContextConfigurator.
SpannerCallContextTimeoutConfigurator now derives from the supplied
context rather than creating a blank default context.
- GapicSpannerRpc:
- Evaluates client-level configurator first, followed by thread-local
configurator (allowing per-call overrides).
- Reliably detects derived vs standalone delta contexts using an internal
CallOptions.Key marker, preventing extra header duplication while
preserving custom CallOptions and internal Spanner routing state.
- Wraps configurator execution exceptions in SpannerException.
- Fixed streaming reads in GapicSpannerRpc to pass getStreamingReadMethod()
instead of getReadMethod().
There was a problem hiding this comment.
Code Review
This pull request introduces support for configuring a client-level CallContextConfigurator in SpannerOptions, allowing users to apply custom gRPC options, timeouts, or credentials client-wide without relying solely on thread-local context propagation. The changes sequentially evaluate client-level and thread-level configurators, merging their options appropriately, and include comprehensive unit tests to verify these behaviors. Feedback on the implementation points out a critical issue where call credentials from a CallCredentialsProvider could be silently wiped out during a merge if a custom configurator returns a standalone delta context with custom CallOptions. A code suggestion is provided to preserve the base credentials in this scenario.
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces support for configuring a client-level CallContextConfigurator in SpannerOptions, allowing users to apply custom gRPC options, timeouts, or credentials client-wide across all RPCs. It updates GapicSpannerRpc to sequentially evaluate both client-level and thread-local configurators, ensuring proper merging of contexts, options, and headers. Additionally, comprehensive unit tests have been added to verify these behaviors. As there are no review comments provided, I have no feedback to evaluate.
🤖 I have created a release *beep* *boop* --- <details><summary>1.91.0</summary> ## [1.91.0](v1.90.0...v1.91.0) (2026-09-04) ### ⚠ BREAKING CHANGES * **datalabeling:** remove java-datalabeling library ([#14189](#14189)) * **datacatalog:** remove java-datacatalog library ([#14178](#14178)) ### Features * **apptopology:** onboard a new library ([#14204](#14204)) ([f871a07](f871a07)) * **bigtable:** Option to disable direct access fallback ([#14193](#14193)) ([5b6a974](5b6a974)) * **datacatalog:** remove java-datacatalog library ([#14178](#14178)) ([2910f63](2910f63)) * **datalabeling:** remove java-datalabeling library ([#14189](#14189)) ([334d35a](334d35a)), refs [#14176](#14176) * **gax:** add getSingleHeader to HttpHeadersUtils ([#14137](#14137)) ([f114422](f114422)) * **gax:** add ResumableUploadClient.startUpload() and supporting types ([#14138](#14138)) ([d7e2be2](d7e2be2)) * **gax:** add ResumableUploadResponseParser ([#14135](#14135)) ([e1a0b17](e1a0b17)) * **gax:** allow non-JSON HttpContent and absolute request URLs in HttpRequestRunnable ([#14134](#14134)) ([ac4a49a](ac4a49a)) * **gax:** implement queryStatusCallable for resumable uploads ([#14155](#14155)) ([67719c0](67719c0)) * **gax:** implement startUploadCallable for resumable uploads ([#14139](#14139)) ([4e65b6c](4e65b6c)) * **gax:** implement uploadChunkCallable for resumable uploads ([#14140](#14140)) ([1c643de](1c643de)) * **google/shopping/merchant/loyaltycustomers/v1:** onboard new library ([#14257](#14257)) ([590a51c](590a51c)) * **grpc-gcp:** drain scaled-down channels ([#14216](#14216)) ([bbbd18c](bbbd18c)) * **grpc-gcp:** move scale-up to background worker ([#14206](#14206)) ([41f0a2e](41f0a2e)) * **grpc-gcp:** penalize retryable channel errors ([#14219](#14219)) ([829872e](829872e)) * **grpc-gcp:** prime scaled channels before publish ([#14232](#14232)) ([dd75645](dd75645)) * **spanner:** add client-level CallContextConfigurator to SpannerOptions ([#14256](#14256)) ([eef74d2](eef74d2)) * **spanner:** prime scaled-up dynamic channel pool channels with SELECT 1 ([#14254](#14254)) ([4d26645](4d26645)) ### Bug Fixes * **auth:** refine JSpecify nullability annotations for external account credentials ([#14164](#14164)) ([385e1f2](385e1f2)) * **bigquery-jdbc:** resolve `statementType` via `getJob` fallback to avoid post-execution dry run for DDL ([#14265](#14265)) ([d38d9f0](d38d9f0)) * **bigtable:** truncate client generated timestamps on the emulator c… ([#14234](#14234)) ([94e680f](94e680f)) * **gax:** propagate structured LRO error details to ApiException ([#14022](#14022)) ([865a15b](865a15b)) * **grpc-gcp:** correct channel lifecycle bookkeeping ([#14196](#14196)) ([3df32ba](3df32ba)) * **grpc-gcp:** prevent hot-channel skew ([#14198](#14198)) ([07a7505](07a7505)) * **java-sql:** temp fix for lint and skip generate ([#14005](#14005)) ([b6f73db](b6f73db)) * **spanner:** prioritize leader replica for read-write transactions in location-aware routing ([#14195](#14195)) ([6383f81](6383f81)) * **spanner:** route ExecuteBatchDml through transaction affinity endpoint ([#14192](#14192)) ([5e9e3cd](5e9e3cd)) * **storage:** resolve GraalVM Native Image test failure for java-storage ([#14226](#14226)) ([93e0920](93e0920)) ### Performance Improvements * **bigquery-jdbc:** eliminate sync getJob RPC call ([#14197](#14197)) ([ccf12b0](ccf12b0)) * **ci:** replace mvn help:evaluate with native bash and sed extraction ([#14218](#14218)) ([744a522](744a522)) ### Dependencies * Upgrade grpc-java to 1.83.0 ([#13967](#13967)) ([0cdc695](0cdc695)) </details> --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --------- Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com>
Adds support for configuring a client-wide CallContextConfigurator via SpannerOptions.Builder#setCallContextConfigurator.
This allows applications (such as async and reactive pipelines where operations span across multiple executor threads) to customize gRPC options, timeouts, and headers across all RPCs without relying on thread-local io.grpc.Context propagation.
Key changes: