Skip to content

Commit 471d12d

Browse files
authored
fix(storage): Handle request transformation after gRPC BidiWriteObject redirects (#16073)
* fix(storage): Handle request transformation correctly after BidiWriteObject 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.
1 parent 7bc7f71 commit 471d12d

10 files changed

Lines changed: 613 additions & 98 deletions

google/cloud/storage/internal/async/connection_impl.cc

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -334,9 +334,11 @@ AsyncConnectionImpl::AppendableObjectUploadImpl(AppendableUploadParams p) {
334334
auto factory = WriteResultFactory(
335335
[stub = stub_, cq = cq_, retry = std::move(retry),
336336
// NOLINTNEXTLINE(bugprone-lambda-function-name)
337-
backoff = std::move(backoff), current, function_name = __func__](
337+
backoff = std::move(backoff), current, function_name = __func__,
338+
// Use shared_ptr to propagate RoutingHeaderOptions across retries.
339+
current_routing_options = std::make_shared<RoutingHeaderOptions>()](
338340
google::storage::v2::BidiWriteObjectRequest req) {
339-
auto call = [stub, request = std::move(req)](
341+
auto call = [stub, request = std::move(req), current_routing_options](
340342
CompletionQueue& cq,
341343
std::shared_ptr<grpc::ClientContext> context,
342344
google::cloud::internal::ImmutableOptions options,
@@ -351,9 +353,11 @@ AsyncConnectionImpl::AppendableObjectUploadImpl(AppendableUploadParams p) {
351353

352354
// Apply the routing header
353355
if (request.has_write_object_spec())
354-
ApplyRoutingHeaders(*context, request.write_object_spec());
356+
ApplyRoutingHeaders(*context, request.write_object_spec(),
357+
*current_routing_options);
355358
else
356-
ApplyRoutingHeaders(*context, request.append_object_spec());
359+
ApplyRoutingHeaders(*context, request.append_object_spec(),
360+
*current_routing_options);
357361

358362
auto rpc = stub->AsyncBidiWriteObject(cq, std::move(context),
359363
std::move(options));
@@ -362,18 +366,30 @@ AsyncConnectionImpl::AppendableObjectUploadImpl(AppendableUploadParams p) {
362366
std::move(rpc));
363367
request.set_state_lookup(true);
364368
auto open = std::make_shared<WriteObject>(std::move(rpc), request);
365-
return open->Call().then([open, &request](auto f) mutable {
366-
open.reset();
367-
auto response = f.get();
368-
if (!response) {
369-
google::rpc::Status grpc_status =
370-
ExtractGrpcStatus(response.status());
371-
EnsureFirstMessageAppendObjectSpec(request, grpc_status);
372-
ApplyWriteRedirectErrors(*request.mutable_append_object_spec(),
373-
grpc_status);
374-
}
375-
return response;
376-
});
369+
return open->Call().then(
370+
[open, &request, current_routing_options](auto f) mutable {
371+
open.reset();
372+
auto response = f.get();
373+
if (!response) {
374+
google::rpc::Status grpc_status =
375+
ExtractGrpcStatus(response.status());
376+
// Handle redirect and get info for updating routing options.
377+
BidiWriteRedirectInfo redirect_info =
378+
HandleBidiWriteRedirect(request, grpc_status);
379+
380+
// Only update the routing token if the new info has a
381+
// non-empty token.
382+
// Otherwise, retain the existing token for subsequent
383+
// retries.
384+
if (!redirect_info.routing_token.empty() &&
385+
current_routing_options->routing_token !=
386+
redirect_info.routing_token) {
387+
current_routing_options->routing_token =
388+
redirect_info.routing_token;
389+
}
390+
}
391+
return response;
392+
});
377393
};
378394

379395
return google::cloud::internal::AsyncRetryLoop(

0 commit comments

Comments
 (0)