Skip to content

feat(Storage): Add x-goog-gcs-idempotency-token idempotency header - #18

Open
mahendra-google wants to merge 1 commit into
mainfrom
feature/add-idempotency-header
Open

mahendra-google wants to merge 1 commit into
mainfrom
feature/add-idempotency-header

Conversation

@mahendra-google

@mahendra-google mahendra-google commented Jun 30, 2026

Copy link
Copy Markdown
Owner

This PR implements automatic injection of the x-goog-gcs-idempotency-token header for retriable requests. This ensures that retries of the same request are recognized as identical by the server, preventing duplicate operations.

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

Copy link
Copy Markdown

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 an idempotency token (x-goog-gcs-idempotency-token) to the retry handler and updates the corresponding tests. The reviewer notes that the token must be sent as a standalone HTTP header rather than being embedded within the x-goog-api-client header. Consequently, the implementation should be updated to add the header directly to the request, the tests should assert on the standalone headers, and the constant should be renamed to reflect this change.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +136 to +139
if (!gotIdempotencyToken)
{
parts.Add(IdempotencyTokenPrefix + Guid.NewGuid());
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

critical

The x-goog-gcs-idempotency-token is a standalone HTTP header used by Google Cloud Storage for request deduplication. It should not be embedded as a parameter inside the x-goog-api-client header (which is what parts represents here). Doing so will cause the GCS backend to ignore the token. Instead, add it directly to the request headers. This also means you can remove IdempotencyTokenPrefix, gotIdempotencyToken, and the corresponding else if block that parses it from parts.

                if (!request.Headers.Contains(IdempotencyTokenHeader))
                {
                    request.Headers.TryAddWithoutValidation(IdempotencyTokenHeader, Guid.NewGuid().ToString());
                }

Comment on lines +483 to +485
var idempotencyToken = request1Parts[idempotencyTokenName];
// Just validate that it's a real GUID...
Guid.Parse(idempotencyToken);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

critical

Since x-goog-gcs-idempotency-token must be sent as a standalone HTTP header rather than part of the x-goog-api-client header, the test should assert on the request's standalone headers directly instead of parsing it from request1Parts.

{
// For testing
internal const string InvocationIdHeaderPart = "gccl-invocation-id";
internal const string IdempotencyTokenHeaderPart = "x-goog-gcs-idempotency-token";

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

Rename this constant to IdempotencyTokenHeader since it is a standalone HTTP header and not a part of another header.

        internal const string IdempotencyTokenHeader = "x-goog-gcs-idempotency-token";

@mahendra-google

Copy link
Copy Markdown
Owner Author

/gemini review

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

Copy link
Copy Markdown

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 introduces an idempotency token (x-goog-gcs-idempotency-token) to the retry handler and updates the tests to verify its presence. However, the test implementation contains a compilation error because it references a non-existent constant RetryHandler.IdempotencyTokenHeaderPart instead of RetryHandler.IdempotencyTokenHeader. Additionally, there is a logic error in the test because the idempotency token is added as a standalone HTTP header, but the test attempts to parse it from the x-goog-api-client header parts, which will cause a runtime exception.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Assert.Equal(3, actualHeaders.Count);

string invocationIdName = RetryHandler.InvocationIdHeaderPart;
string idempotencyTokenName = RetryHandler.IdempotencyTokenHeaderPart;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

There are two major issues with this test implementation:\n\n1. Compilation Error: RetryHandler.IdempotencyTokenHeaderPart does not exist. The constant defined in RetryHandler.cs is IdempotencyTokenHeader.\n2. Logic Error / Test Failure: x-goog-gcs-idempotency-token is added as a standalone HTTP header, whereas gccl-invocation-id and gccl-attempt-count are parts of the x-goog-api-client header. Since ReplayingMessageHandler is initialized with VersionHeaderBuilder.HeaderName (x-goog-api-client), actualHeaders only contains the values of the x-goog-api-client header. Because the idempotency token is a separate header, it will not be present in actualHeaders, and attempting to look it up via request1Parts[idempotencyTokenName] will throw a KeyNotFoundException at runtime.\n\nYou will need to reference RetryHandler.IdempotencyTokenHeader and update the test assertion logic to inspect the standalone x-goog-gcs-idempotency-token header directly from the requests.

            string idempotencyTokenName = RetryHandler.IdempotencyTokenHeader;

@mahendra-google

Copy link
Copy Markdown
Owner Author

/gemini review

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

Copy link
Copy Markdown

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 support for an idempotency token header (x-goog-gcs-idempotency-token) in the RetryHandler class of Google.Cloud.Storage.V1. If the header is missing from the outgoing request, a new GUID is generated and added. There are no review comments, and I have no feedback to provide.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

@mahendra-google

Copy link
Copy Markdown
Owner Author

/gemini review

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

Copy link
Copy Markdown

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 introduces an IdempotencyTokenInterceptor to automatically attach a unique idempotency token (x-goog-gcs-idempotency-token) to retriable Google Cloud Storage requests, and adds a unit test to verify this behavior. The review feedback suggests strengthening the unit test by asserting that the idempotency token is present and consistent across all retry attempts, rather than filtering out empty headers which could mask missing tokens.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +513 to +523
var validTokens = actualHeaders
.Where(token => !string.IsNullOrEmpty(token))
.Where(guidStr => guidStr != null)
.ToList();

Assert.NotEmpty(validTokens);

var firstToken = validTokens.First();
// Just validate that it's a real GUID...
Guid.Parse(firstToken);
Assert.All(validTokens, token => Assert.Equal(firstToken, token));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

The test currently filters out null or empty tokens using .Where(token => !string.IsNullOrEmpty(token)). This means if the idempotency header is missing on any of the retried requests, the test will still pass as long as at least one request has the header.

To ensure that the idempotency token is correctly set on every attempt (including all retries), we should assert that the number of captured headers matches the expected number of requests (3), and that none of them are null or empty.

            Assert.Equal(3, actualHeaders.Count);
            Assert.All(actualHeaders, token => Assert.False(string.IsNullOrEmpty(token)));

            var firstToken = actualHeaders.First();
            // Just validate that it's a real GUID...
            Guid.Parse(firstToken);
            Assert.All(actualHeaders, token => Assert.Equal(firstToken, token));

@mahendra-google

Copy link
Copy Markdown
Owner Author

/gemini review

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

Copy link
Copy Markdown

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 introduces an automatic idempotency token header (x-goog-gcs-idempotency-token) for retriable requests. This is achieved by adding a new IdempotencyTokenInterceptor that injects a unique GUID into the request headers if it is not already present. Additionally, a unit test has been added to verify that the idempotency header is correctly set and preserved across retried requests. There are no review comments, and I have no feedback to provide.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

@mahendra-google mahendra-google changed the title feat(Storage): Add idempotency header feat(Storage): Add x-goog-gcs-idempotency-token idempotency header Jun 30, 2026
@mahendra-google
mahendra-google force-pushed the feature/add-idempotency-header branch from c05d8a6 to c5d20aa Compare July 1, 2026 06:57
@mahendra-google
mahendra-google force-pushed the feature/add-idempotency-header branch from d3d3b80 to d720432 Compare September 16, 2026 10:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants