Skip to content

fix(storage): add retry support for finalize and close in AsyncAppendableObjectWriter - #17733

Open
sahusneha2004 wants to merge 1 commit into
googleapis:mainfrom
sahusneha2004:fix-appendable-writer-finalize-retry
Open

fix(storage): add retry support for finalize and close in AsyncAppendableObjectWriter#17733
sahusneha2004 wants to merge 1 commit into
googleapis:mainfrom
sahusneha2004:fix-appendable-writer-finalize-retry

Conversation

@sahusneha2004

@sahusneha2004 sahusneha2004 commented Jul 16, 2026

Copy link
Copy Markdown

This PR introduces robust retry support for the close() and finalize() operations on bidirectional gRPC appendable streams (AsyncAppendableObjectWriter). Previously, if a transient error (such as a 503 Unavailable or a redirect error) occurred exactly when sending the finish_write signal, the stream would fail without attempting to recover.

This change ensures that close() and finalize() respect the configured retry_policy and can seamlessly reconnect and retry the finalization if a transient failure or backend redirection occurs.

Key Changes:

Added Retry Loop in Finalize: Refactored finalize() to wrap the gRPC requests_done() and response logic inside a new _do_finalize() helper function. This function uses a retry loop to catch transient exceptions.
Stream Re-initialization on Retry: If a retriable error occurs during finalize, _do_finalize() will safely attempt to re-open the stream via await self.open(metadata=metadata) and re-send the finish_write=True signal to successfully close out the object.
Metadata Pass-through: Added an optional metadata parameter to both close() and finalize(). This ensures that any custom gRPC headers (such as x-retry-test-id used by the Storage Testbench) are preserved and correctly passed to self.open() if a retry connection needs to be established.

Testing:
Unit Tests: Updated tests/unit/asyncio/test_async_appendable_object_writer.py to assert the new metadata argument signatures and verify the retry logic mock calls.
Integration Tests: Added new conformance test scenarios in tests/conformance/test_bidi_writes.py ("name": "Retry on 503 during close/finalize") utilizing the empty_write: True flag. This successfully verifies the retry mechanisms against the Storage Testbench emulator, including both 503 Unavailable and BidiWriteObjectRedirectedError (Redirect Error) faults during finalization.

Fixes: b/532527637

@sahusneha2004
sahusneha2004 requested a review from a team as a code owner July 16, 2026 09:19

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

Copy link
Copy Markdown
Contributor

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 custom and default retry policies during the finalization and closing of an asynchronous appendable object writer, along with corresponding unit tests. However, the current implementation of the retry mechanism in finalize is flawed because it attempts to reuse the same gRPC stream (write_obj_stream) after an error has occurred. In production, a gRPC stream enters an errored state and closes upon failure, meaning subsequent retries on the same stream will fail immediately. To resolve this, the underlying stream must be re-established or recreated before retrying.

@sahusneha2004
sahusneha2004 force-pushed the fix-appendable-writer-finalize-retry branch 2 times, most recently from 208879e to 3366eb0 Compare July 16, 2026 10:34
@parthea
parthea requested a review from chandra-siri July 16, 2026 14:16
@sahusneha2004
sahusneha2004 force-pushed the fix-appendable-writer-finalize-retry branch 7 times, most recently from b509e2e to 2bc1f95 Compare July 22, 2026 10:56
@sahusneha2004
sahusneha2004 force-pushed the fix-appendable-writer-finalize-retry branch from 2bc1f95 to b2ce145 Compare July 22, 2026 10:59
@chandra-siri

Copy link
Copy Markdown
Contributor

@sahusneha2004 unit tests are failing. Add Description as well.

Comment thread packages/google-cloud-storage/tests/conformance/test_bidi_writes.py
if (
self.offset is not None
and expected_offset is not None
and self.offset < expected_offset

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

make it != instead of < . There could be a scenario where another writer might have written data to the same object

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

make the same change in _do_finalize() as well.


assert res == resource
assert writer.persisted_size == 999
assert mock_appendable_writer["mock_stream"].send.await_count == 2

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

add await_count on recvassert mock_appendable_writer["mock_stream"].recv.await_count == 2

].recv.return_value = storage_type.BidiWriteObjectResponse(resource=resource)

res = await writer.finalize(retry_policy=custom_policy)
assert res == resource

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

what about other other assert statements , similar to above test case ? test_finalize_retry_on_transient_error

writer.finalize.assert_awaited_once_with(
full_object_checksum=None,
retry_policy=custom_policy,
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

add more assert statements similar to onces in test_close_retry_on_transient_error

@chandra-siri

Copy link
Copy Markdown
Contributor

@sahusneha2004 merge this PR only after googleapis/storage-testbench#811 is merged.

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