From cf920da45d77f667050e9f1e50db6cd8ce20022e Mon Sep 17 00:00:00 2001 From: Michael Herold Date: Mon, 3 Nov 2025 12:02:00 -0600 Subject: [PATCH 1/2] bug: Don't route to leader for single use txns This change makes it so queries against single-use transactions do not route to the leader, even when leader-aware routing is enabled, as these single-use transactions are read-only transactions with specific staleness requirements. --- .../lib/google/cloud/spanner/client.rb | 2 +- .../client/execute_query_test.rb | 51 ++++++++++++++++++- 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/google-cloud-spanner/lib/google/cloud/spanner/client.rb b/google-cloud-spanner/lib/google/cloud/spanner/client.rb index 72e00ae4..d83b83ab 100644 --- a/google-cloud-spanner/lib/google/cloud/spanner/client.rb +++ b/google-cloud-spanner/lib/google/cloud/spanner/client.rb @@ -484,7 +484,7 @@ def execute_query sql, params: nil, types: nil, single_use: nil, request_options = Convert.to_request_options request_options, tag_type: :request_tag single_use_tx = single_use_transaction single_use - route_to_leader = LARHeaders.execute_query true + route_to_leader = LARHeaders.execute_query !single_use_tx results = nil @pool.with_session do |session| results = session.execute_query \ diff --git a/google-cloud-spanner/test/google/cloud/spanner/leader_aware_routing/client/execute_query_test.rb b/google-cloud-spanner/test/google/cloud/spanner/leader_aware_routing/client/execute_query_test.rb index d9580e1b..747babd4 100644 --- a/google-cloud-spanner/test/google/cloud/spanner/leader_aware_routing/client/execute_query_test.rb +++ b/google-cloud-spanner/test/google/cloud/spanner/leader_aware_routing/client/execute_query_test.rb @@ -60,7 +60,7 @@ mock.verify end - it "sends header x-goog-spanner-route-to-leader when LAR is enabled" do + it "sends header x-goog-spanner-route-to-leader with true for queries without single_use when LAR is enabled" do mock = Minitest::Mock.new mock.expect :create_session, session_grpc do |request, gapic_options| gapic_options.metadata["x-goog-spanner-route-to-leader"] == 'true' @@ -75,4 +75,53 @@ mock.verify end + + it "sends header x-goog-spanner-route-to-leader with false for queries with single_use strong option when LAR is enabled" do + mock = Minitest::Mock.new + mock.expect :create_session, session_grpc do |request, gapic_options| + gapic_options.metadata["x-goog-spanner-route-to-leader"] == 'true' + end + mock.expect :execute_streaming_sql, results_enum do |request, gapic_options| + gapic_options.metadata["x-goog-spanner-route-to-leader"] == 'false' + end + spanner.service.mocked_service = mock + + spanner.service.enable_leader_aware_routing = true + results = client.execute_query "SELECT 1", single_use: { strong: true } + + mock.verify + end + + it "sends header x-goog-spanner-route-to-leader with false for queries with single_use staleness option when LAR is enabled" do + mock = Minitest::Mock.new + mock.expect :create_session, session_grpc do |request, gapic_options| + gapic_options.metadata["x-goog-spanner-route-to-leader"] == 'true' + end + mock.expect :execute_streaming_sql, results_enum do |request, gapic_options| + gapic_options.metadata["x-goog-spanner-route-to-leader"] == 'false' + end + spanner.service.mocked_service = mock + + spanner.service.enable_leader_aware_routing = true + results = client.execute_query "SELECT 1", single_use: { staleness: 60 } + + mock.verify + end + + it "sends header x-goog-spanner-route-to-leader with false for queries with single_use timestamp option when LAR is enabled" do + mock = Minitest::Mock.new + mock.expect :create_session, session_grpc do |request, gapic_options| + gapic_options.metadata["x-goog-spanner-route-to-leader"] == 'true' + end + mock.expect :execute_streaming_sql, results_enum do |request, gapic_options| + gapic_options.metadata["x-goog-spanner-route-to-leader"] == 'false' + end + spanner.service.mocked_service = mock + + spanner.service.enable_leader_aware_routing = true + timestamp = Time.now - 60 + results = client.execute_query "SELECT 1", single_use: { timestamp: timestamp } + + mock.verify + end end From 70a221b72b02244c54dcf537e935184353780272 Mon Sep 17 00:00:00 2001 From: Viacheslav Rostovtsev Date: Thu, 6 Nov 2025 17:39:15 +0000 Subject: [PATCH 2/2] fixup: always send false --- google-cloud-spanner/lib/google/cloud/spanner/client.rb | 2 +- .../spanner/leader_aware_routing/client/execute_query_test.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/google-cloud-spanner/lib/google/cloud/spanner/client.rb b/google-cloud-spanner/lib/google/cloud/spanner/client.rb index d83b83ab..cc000ef3 100644 --- a/google-cloud-spanner/lib/google/cloud/spanner/client.rb +++ b/google-cloud-spanner/lib/google/cloud/spanner/client.rb @@ -484,7 +484,7 @@ def execute_query sql, params: nil, types: nil, single_use: nil, request_options = Convert.to_request_options request_options, tag_type: :request_tag single_use_tx = single_use_transaction single_use - route_to_leader = LARHeaders.execute_query !single_use_tx + route_to_leader = LARHeaders.execute_query false results = nil @pool.with_session do |session| results = session.execute_query \ diff --git a/google-cloud-spanner/test/google/cloud/spanner/leader_aware_routing/client/execute_query_test.rb b/google-cloud-spanner/test/google/cloud/spanner/leader_aware_routing/client/execute_query_test.rb index 747babd4..f3973800 100644 --- a/google-cloud-spanner/test/google/cloud/spanner/leader_aware_routing/client/execute_query_test.rb +++ b/google-cloud-spanner/test/google/cloud/spanner/leader_aware_routing/client/execute_query_test.rb @@ -66,7 +66,7 @@ gapic_options.metadata["x-goog-spanner-route-to-leader"] == 'true' end mock.expect :execute_streaming_sql, results_enum do |request, gapic_options| - gapic_options.metadata["x-goog-spanner-route-to-leader"] == 'true' + gapic_options.metadata["x-goog-spanner-route-to-leader"] == 'false' end spanner.service.mocked_service = mock