Skip to content

fix(storage): Handle request transformation after gRPC BidiWriteObject redirects#16073

Open
kalragauri wants to merge 1 commit intogoogleapis:mainfrom
kalragauri:feature/append-object
Open

fix(storage): Handle request transformation after gRPC BidiWriteObject redirects#16073
kalragauri wants to merge 1 commit intogoogleapis:mainfrom
kalragauri:feature/append-object

Conversation

@kalragauri
Copy link
Copy Markdown

This commit addresses an issue where gRPC BidiWriteObject operations, particularly in cross-region redirect scenarios, would fail with a NOT_FOUND error. The root cause was that bucket information was not propagated in the request headers after the client received a redirect error from the service.

@product-auto-label product-auto-label bot added the api: storage Issues related to the Cloud Storage API. label Apr 8, 2026
Copy link
Copy Markdown

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

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 the propagation of routing tokens across retries for asynchronous appendable uploads. It introduces a RoutingHeaderOptions structure to manage tokens in gRPC metadata and adds the HandleBidiWriteRedirect utility to centralize redirect handling and request specification updates. Feedback identifies that the call to HandleBidiWriteRedirect within AsyncWriterConnectionImpl::OnQuery is ineffective, as the modified request state is not preserved or propagated back to the higher-level retry loop in AsyncConnectionImpl.

EnsureFirstMessageAppendObjectSpec(request_, grpc_status);
ApplyWriteRedirectErrors(*request_.mutable_append_object_spec(),
grpc_status);
HandleBidiWriteRedirect(request_, grpc_status);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The call to HandleBidiWriteRedirect here appears to have no effect. This function modifies the request_ member, but OnQuery is a destructive operation that closes the stream, rendering this AsyncWriterConnectionImpl instance unusable. The retry logic that would benefit from the modified request exists at a higher level (in AsyncConnectionImpl) and creates a new writer connection for each attempt. The state from this failed connection, including the modified request_, is not propagated.

Since the modifications to request_ are lost, this call can be removed. Note that removing this line will cause the grpc_status variable on the preceding line to be unused, so that line should probably be removed as well.

@kalragauri kalragauri force-pushed the feature/append-object branch from 18a62db to 30b6578 Compare April 8, 2026 11:57
@codecov
Copy link
Copy Markdown

codecov bot commented Apr 8, 2026

Codecov Report

❌ Patch coverage is 99.73615% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 92.71%. Comparing base (fc9f8f0) to head (56269bc).
⚠️ Report is 6 commits behind head on main.

Files with missing lines Patch % Lines
...al/async/connection_impl_appendable_upload_test.cc 99.48% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #16073      +/-   ##
==========================================
+ Coverage   92.69%   92.71%   +0.01%     
==========================================
  Files        2343     2343              
  Lines      216674   216989     +315     
==========================================
+ Hits       200852   201172     +320     
+ Misses      15822    15817       -5     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

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

google::storage::v2::AppendObjectSpec const& spec,
RoutingHeaderOptions const& options) {
std::string params =
"bucket=" + google::cloud::internal::UrlEncode(spec.bucket());
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It appears the only difference between these two functions is whether or not to call spec.bucket() or spec.resource().bucket(). Considering the number of identical string literals that have to be correct in both functions. I would recommend factoring out a helper function that contains the common code.

params += "&routing_token=" +
google::cloud::internal::UrlEncode(options.routing_token);
}
context.AddMetadata("x-goog-request-params", params);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

std::move(params)

@scotthart scotthart marked this pull request as ready for review April 8, 2026 15:45
@scotthart scotthart requested review from a team as code owners April 8, 2026 15:45
…Object redirects

This commit addresses an issue where BidiWriteObject operations, particularly in cross-region redirect scenarios, would fail with a NOT_FOUND error. The root cause was that bucket information was not propagated in the request headers after the client received a redirect error from the service.
@kalragauri kalragauri force-pushed the feature/append-object branch from 30b6578 to 56269bc Compare April 8, 2026 15:51
@kalragauri kalragauri requested a review from v-pratap April 8, 2026 15:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api: storage Issues related to the Cloud Storage API.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants