Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,11 @@ pip install google-cloud-testutils google-cloud-kms
pip install google-cloud-storage[grpc,testing]

echo '--- Setting up environment variables on VM ---'
export ZONAL_BUCKET=${_ZONAL_BUCKET}
export RUN_ZONAL_SYSTEM_TESTS=True
export RAPID_BUCKET="${_RAPID_BUCKET:-${_ZONAL_BUCKET:-}}"
export ZONAL_BUCKET="${RAPID_BUCKET}"
Comment on lines +43 to +44

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Since zb-system-tests-cloudbuild.yaml now defaults _ZONAL_BUCKET to "", RAPID_BUCKET can silently evaluate to an empty string without triggering set -u. Failing fast here avoids running all 9 pytest tests against an empty bucket name if trigger substitutions are misconfigured.

Suggested change
export RAPID_BUCKET="${_RAPID_BUCKET:-${_ZONAL_BUCKET:-}}"
export ZONAL_BUCKET="${RAPID_BUCKET}"
export RAPID_BUCKET="${_RAPID_BUCKET:-${_ZONAL_BUCKET:-}}"
: "${RAPID_BUCKET:?Either _RAPID_BUCKET or _ZONAL_BUCKET must be set and non-empty}"
export ZONAL_BUCKET="${RAPID_BUCKET}"

export RUN_RAPID_SYSTEM_TESTS=True
export RUN_BIDI_SYSTEM_TESTS=True
export GCE_METADATA_MTLS_MODE=None
CURRENT_ULIMIT=$(ulimit -n)
echo '--- Running Zonal tests on VM with ulimit set to ---' $CURRENT_ULIMIT
pytest -vv -s --log-format='%(asctime)s %(levelname)s %(message)s' --log-date-format='%H:%M:%S' samples/snippets/zonal_buckets/zonal_snippets_test.py
echo '--- Running Rapid bucket (bidi) tests on VM with ulimit set to ---' $CURRENT_ULIMIT
pytest -vv -s --log-format='%(asctime)s %(levelname)s %(message)s' --log-date-format='%H:%M:%S' samples/snippets/bidi/bidi_snippets_test.py
8 changes: 6 additions & 2 deletions storage/cloudbuild/zb-system-tests-cloudbuild.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ substitutions:
_SHORT_BUILD_ID: ${BUILD_ID:0:8}
_VM_NAME: "py-sdk-sys-test-${_SHORT_BUILD_ID}"
_ULIMIT: "10000" # 10k, for gRPC bidi streams
# Name of the rapid bucket used by the bidi samples tests. Set by the trigger.
_ZONAL_BUCKET: ""
# Service account attached to the test VM. Set by the trigger.
_ZONAL_VM_SERVICE_ACCOUNT: ""
Comment on lines +22 to +25

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.

medium

To allow future Cloud Build triggers to transition to using _RAPID_BUCKET directly without breaking, define _RAPID_BUCKET in the substitutions block. This ensures that when the trigger is updated to pass _RAPID_BUCKET, Cloud Build won't fail due to an undefined substitution variable.

  # Name of the rapid bucket used by the bidi samples tests. Set by the trigger.
  _RAPID_BUCKET: ""
  _ZONAL_BUCKET: ""
  # Service account attached to the test VM. Set by the trigger.
  _ZONAL_VM_SERVICE_ACCOUNT: ""

Comment on lines +22 to +25

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

+1 to adding _RAPID_BUCKET: "" here and passing _RAPID_BUCKET=${_RAPID_BUCKET} on line 125 so Cloud Build's strict substitution check allows updating the trigger later.

Please also declare _CROSS_REGION_BUCKET: "" here (since line 125 references ${_CROSS_REGION_BUCKET} and existing triggers may still pass it), or consider adding _RAPID_VM_SERVICE_ACCOUNT: "" if the trigger's service account substitution will also be renamed.

  # Name of the bucket (Rapid storage class) used by the bidi samples tests.
  _RAPID_BUCKET: ""
  _ZONAL_BUCKET: ""
  _CROSS_REGION_BUCKET: ""
  # Service account attached to the test VM. Set by the trigger.
  _ZONAL_VM_SERVICE_ACCOUNT: ""




Expand Down Expand Up @@ -113,12 +117,12 @@ steps:
sleep 15
done
# copy the script to the VM
gcloud compute scp storage/cloudbuild/run_zonal_tests.sh ${_VM_NAME}:~ --zone=${_ZONE} --internal-ip --ssh-key-file=/workspace/.ssh/google_compute_engine
gcloud compute scp storage/cloudbuild/run_rapid_tests.sh ${_VM_NAME}:~ --zone=${_ZONE} --internal-ip --ssh-key-file=/workspace/.ssh/google_compute_engine

# Execute the script on the VM via SSH.
# Capture the exit code to ensure cleanup happens before the build fails.
set +e
gcloud compute ssh ${_VM_NAME} --zone=${_ZONE} --internal-ip --ssh-key-file=/workspace/.ssh/google_compute_engine --command="ulimit -n ${_ULIMIT}; COMMIT_SHA=${COMMIT_SHA} _ZONAL_BUCKET=${_ZONAL_BUCKET} CROSS_REGION_BUCKET=${_CROSS_REGION_BUCKET} _PR_NUMBER=${_PR_NUMBER} bash run_zonal_tests.sh"
gcloud compute ssh ${_VM_NAME} --zone=${_ZONE} --internal-ip --ssh-key-file=/workspace/.ssh/google_compute_engine --command="ulimit -n ${_ULIMIT}; COMMIT_SHA=${COMMIT_SHA} _RAPID_BUCKET=${_ZONAL_BUCKET} _ZONAL_BUCKET=${_ZONAL_BUCKET} CROSS_REGION_BUCKET=${_CROSS_REGION_BUCKET} _PR_NUMBER=${_PR_NUMBER} bash run_rapid_tests.sh"

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.

medium

Pass _RAPID_BUCKET=${_RAPID_BUCKET} instead of hardcoding it to ${_ZONAL_BUCKET}. Since run_rapid_tests.sh already has fallback logic (RAPID_BUCKET="${_RAPID_BUCKET:-${_ZONAL_BUCKET:-}}"), this change allows the script to correctly receive either variable depending on which one is configured in the trigger.

        gcloud compute ssh ${_VM_NAME} --zone=${_ZONE} --internal-ip --ssh-key-file=/workspace/.ssh/google_compute_engine --command="ulimit -n ${_ULIMIT}; COMMIT_SHA=${COMMIT_SHA} _RAPID_BUCKET=${_RAPID_BUCKET} _ZONAL_BUCKET=${_ZONAL_BUCKET} CROSS_REGION_BUCKET=${_CROSS_REGION_BUCKET} _PR_NUMBER=${_PR_NUMBER} bash run_rapid_tests.sh"

EXIT_CODE=$?
set -e

Expand Down
91 changes: 91 additions & 0 deletions storage/samples/snippets/bidi/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Google Cloud Storage - Bidirectional Streaming (Bidi) Snippets

This directory contains snippets that use the Google Cloud Storage gRPC
bidirectional streaming (bidi) APIs, including appendable object writes and
multi-range reads.

## Prerequisites

- A Google Cloud Platform project with the Cloud Storage API enabled.
- For the appendable object snippets (create, finalize, pause and resume, tail,
and the pre-warmed writer pool), a rapid bucket (a bucket with the Rapid
storage class).
- The ranged read snippets work with any Google Cloud Storage bucket.

## Running the snippets

### Create and write to an appendable object

This snippet uploads an appendable object to a rapid bucket.

```bash
python samples/snippets/bidi/storage_create_and_write_appendable_object.py --bucket_name <bucket_name> --object_name <object_name>
```
Comment on lines +7 to +23

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Three usability fixes for this README:

  1. Invocation paths: python samples/snippets/bidi/... only works if the user cds into storage/ first. Please use python storage/samples/snippets/bidi/... (from repo root, matching googleapis/google-cloud-python#18859) across all 9 commands, or add a cd storage step under Setup.
  2. Missing [grpc] dependency prerequisite: storage/samples/snippets/requirements.txt installs google-cloud-storage without the grpc extra. Please document pip install "google-cloud-storage[grpc]" under Prerequisites.
  3. Terminology & formatting: Replace "a rapid bucket" (lines 11, 19, 87) with "a bucket with the Rapid storage class", replace "Google Cloud Platform" with "Google Cloud", remove extra blank lines (lines 48–49, 57–58, 74–76), and add a trailing newline at EOF.
Suggested change
## Prerequisites
- A Google Cloud Platform project with the Cloud Storage API enabled.
- For the appendable object snippets (create, finalize, pause and resume, tail,
and the pre-warmed writer pool), a rapid bucket (a bucket with the Rapid
storage class).
- The ranged read snippets work with any Google Cloud Storage bucket.
## Running the snippets
### Create and write to an appendable object
This snippet uploads an appendable object to a rapid bucket.
```bash
python samples/snippets/bidi/storage_create_and_write_appendable_object.py --bucket_name <bucket_name> --object_name <object_name>
```
## Prerequisites
- A Google Cloud project with the Cloud Storage API enabled.
- The Cloud Storage library installed with gRPC support:
```bash
pip install "google-cloud-storage[grpc]"
```
- For the appendable object snippets (create, finalize, pause and resume, tail,
and the pre-warmed writer pool), a bucket with the Rapid storage class.
- The ranged read snippets work with any Google Cloud Storage bucket.
## Running the snippets
Run the commands below from the repository root:
### Create and write to an appendable object
This snippet uploads an appendable object to a bucket with the Rapid storage class.
```bash
python storage/samples/snippets/bidi/storage_create_and_write_appendable_object.py --bucket_name <bucket_name> --object_name <object_name>
```


### Finalize an appendable object upload

This snippet creates, writes to, and finalizes an appendable object.

```bash
python samples/snippets/bidi/storage_finalize_appendable_object_upload.py --bucket_name <bucket_name> --object_name <object_name>
```

### Pause and resume an appendable object upload

This snippet demonstrates pausing and resuming an appendable object upload.

```bash
python samples/snippets/bidi/storage_pause_and_resume_appendable_upload.py --bucket_name <bucket_name> --object_name <object_name>
```

### Tail an appendable object

This snippet demonstrates tailing an appendable GCS object, similar to `tail -f`.

```bash
python samples/snippets/bidi/storage_read_appendable_object_tail.py --bucket_name <bucket_name> --object_name <object_name> --duration <duration_in_seconds>
```


### Download a range of bytes from an object

This snippet downloads a range of bytes from an object.

```bash
python samples/snippets/bidi/storage_open_object_single_ranged_read.py --bucket_name <bucket_name> --object_name <object_name> --start_byte <start_byte> --size <size>
```


### Download multiple ranges of bytes from a single object

This snippet downloads multiple ranges of bytes from a single object into different buffers.

```bash
python samples/snippets/bidi/storage_open_object_multiple_ranged_read.py --bucket_name <bucket_name> --object_name <object_name>
```

### Download the entire content of an object

This snippet downloads the entire content of an object using a multi-range downloader.

```bash
python samples/snippets/bidi/storage_open_object_read_full_object.py --bucket_name <bucket_name> --object_name <object_name>
```



### Download a range of bytes from multiple objects concurrently

This snippet downloads a range of bytes from multiple objects concurrently.

```bash
python samples/snippets/bidi/storage_open_multiple_objects_ranged_read.py --bucket_name <bucket_name> --object_names <object_name_1> <object_name_2>
```

### Optimize write latency with a pre-warmed writer pool

This snippet uses a pre-warmed pool of writers for appendable objects in a rapid bucket.

```bash
python samples/snippets/bidi/storage_optimize_write_latency_pool.py --bucket_name <bucket_name> --key_prefix <key_prefix>
```
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,21 @@
import storage_read_appendable_object_tail

pytestmark = pytest.mark.skipif(
os.getenv("RUN_ZONAL_SYSTEM_TESTS") != "True",
reason="Zonal system tests need to be explicitly enabled. This helps scheduling tests in Kokoro and Cloud Build.",
not any(
os.getenv(v) == "True"
for v in (
"RUN_RAPID_SYSTEM_TESTS",
"RUN_BIDI_SYSTEM_TESTS",
"RUN_ZONAL_SYSTEM_TESTS",
)
),
reason="Rapid bucket (bidi) system tests need to be explicitly enabled. This helps scheduling tests in Kokoro and Cloud Build.",
)


# TODO: replace this with a fixture once zonal bucket creation / deletion
# TODO: replace this with a fixture once rapid bucket creation / deletion
# is supported in grpc client or json client client.
_ZONAL_BUCKET = os.getenv("ZONAL_BUCKET")
_RAPID_BUCKET = os.getenv("RAPID_BUCKET") or os.getenv("ZONAL_BUCKET")
Comment on lines +47 to +53

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Minor cleanups here:

  1. Mention RUN_BIDI_SYSTEM_TESTS=True in the skipif reason (Kokoro is no longer active on this repo) and fix the "json client client" typo on line 52.
  2. Optionally assert or fail clearly if tests are enabled while _RAPID_BUCKET is unset, so local runs get an actionable error message.
Suggested change
reason="Rapid bucket (bidi) system tests need to be explicitly enabled. This helps scheduling tests in Kokoro and Cloud Build.",
)
# TODO: replace this with a fixture once zonal bucket creation / deletion
# TODO: replace this with a fixture once rapid bucket creation / deletion
# is supported in grpc client or json client client.
_ZONAL_BUCKET = os.getenv("ZONAL_BUCKET")
_RAPID_BUCKET = os.getenv("RAPID_BUCKET") or os.getenv("ZONAL_BUCKET")
reason="Bidi system tests must be explicitly enabled (e.g., RUN_BIDI_SYSTEM_TESTS=True).",
)
# TODO: replace this with a fixture once creating a bucket with the Rapid
# storage class is supported in the test setup.
_RAPID_BUCKET = os.getenv("RAPID_BUCKET") or os.getenv("ZONAL_BUCKET")



async def create_async_grpc_client():
Expand Down Expand Up @@ -77,7 +84,7 @@ def json_client():
async def create_appendable_object(grpc_client, object_name, data):
writer = AsyncAppendableObjectWriter(
client=grpc_client,
bucket_name=_ZONAL_BUCKET,
bucket_name=_RAPID_BUCKET,
object_name=object_name,
generation=0, # throws `FailedPrecondition` if object already exists.
)
Expand All @@ -87,25 +94,20 @@ async def create_appendable_object(grpc_client, object_name, data):
return writer.generation


# TODO: replace this with a fixture once zonal bucket creation / deletion
# is supported in grpc client or json client client.
_ZONAL_BUCKET = os.getenv("ZONAL_BUCKET")


def test_storage_create_and_write_appendable_object(
async_grpc_client, json_client, event_loop, capsys
):
object_name = f"zonal-snippets-test-{uuid.uuid4()}"
object_name = f"bidi-snippets-test-{uuid.uuid4()}"

event_loop.run_until_complete(
storage_create_and_write_appendable_object.storage_create_and_write_appendable_object(
_ZONAL_BUCKET, object_name, grpc_client=async_grpc_client
_RAPID_BUCKET, object_name, grpc_client=async_grpc_client
)
)
out, _ = capsys.readouterr()
assert f"Appended object {object_name} created of size" in out

blob = json_client.bucket(_ZONAL_BUCKET).blob(object_name)
blob = json_client.bucket(_RAPID_BUCKET).blob(object_name)
blob.delete()


Expand All @@ -115,12 +117,12 @@ def test_storage_finalize_appendable_object_upload(
object_name = f"test-finalize-appendable-{uuid.uuid4()}"
event_loop.run_until_complete(
storage_finalize_appendable_object_upload.storage_finalize_appendable_object_upload(
_ZONAL_BUCKET, object_name, grpc_client=async_grpc_client
_RAPID_BUCKET, object_name, grpc_client=async_grpc_client
)
)
out, _ = capsys.readouterr()
assert f"Appendable object {object_name} created and finalized." in out
blob = json_client.bucket(_ZONAL_BUCKET).get_blob(object_name)
blob = json_client.bucket(_RAPID_BUCKET).get_blob(object_name)
blob.delete()


Expand All @@ -130,14 +132,14 @@ def test_storage_pause_and_resume_appendable_upload(
object_name = f"test-pause-resume-{uuid.uuid4()}"
event_loop.run_until_complete(
storage_pause_and_resume_appendable_upload.storage_pause_and_resume_appendable_upload(
_ZONAL_BUCKET, object_name, grpc_client=async_grpc_client
_RAPID_BUCKET, object_name, grpc_client=async_grpc_client
)
)
out, _ = capsys.readouterr()
assert "First writer closed. Upload is 'paused'." in out
assert "Second writer closed. Full object uploaded." in out

blob = json_client.bucket(_ZONAL_BUCKET).get_blob(object_name)
blob = json_client.bucket(_RAPID_BUCKET).get_blob(object_name)
blob.delete()


Expand All @@ -147,7 +149,7 @@ def test_storage_read_appendable_object_tail(
object_name = f"test-read-tail-{uuid.uuid4()}"
event_loop.run_until_complete(
storage_read_appendable_object_tail.read_appendable_object_tail(
_ZONAL_BUCKET, object_name, duration=3, grpc_client=async_grpc_client
_RAPID_BUCKET, object_name, duration=3, grpc_client=async_grpc_client
)
)
out, _ = capsys.readouterr()
Expand All @@ -158,7 +160,7 @@ def test_storage_read_appendable_object_tail(
assert "Tailer finished." in out
assert "Writer closed." in out

bucket = json_client.bucket(_ZONAL_BUCKET)
bucket = json_client.bucket(_RAPID_BUCKET)
blob = bucket.blob(object_name)
blob.delete()

Expand All @@ -173,15 +175,15 @@ def test_storage_open_object_read_full_object(
)
event_loop.run_until_complete(
storage_open_object_read_full_object.storage_open_object_read_full_object(
_ZONAL_BUCKET, object_name, grpc_client=async_grpc_client
_RAPID_BUCKET, object_name, grpc_client=async_grpc_client
)
)
out, _ = capsys.readouterr()
assert (
f"Downloaded all {len(data)} bytes from object {object_name} in bucket {_ZONAL_BUCKET}."
f"Downloaded all {len(data)} bytes from object {object_name} in bucket {_RAPID_BUCKET}."
in out
)
blob = json_client.bucket(_ZONAL_BUCKET).blob(object_name)
blob = json_client.bucket(_RAPID_BUCKET).blob(object_name)
blob.delete()


Expand All @@ -197,7 +199,7 @@ def test_storage_open_object_single_ranged_read(
download_size = 5
event_loop.run_until_complete(
storage_open_object_single_ranged_read.storage_open_object_single_ranged_read(
_ZONAL_BUCKET,
_RAPID_BUCKET,
object_name,
start_byte=0,
size=download_size,
Expand All @@ -206,7 +208,7 @@ def test_storage_open_object_single_ranged_read(
)
out, _ = capsys.readouterr()
assert f"Downloaded {download_size} bytes from {object_name}" in out
blob = json_client.bucket(_ZONAL_BUCKET).blob(object_name)
blob = json_client.bucket(_RAPID_BUCKET).blob(object_name)
blob.delete()


Expand All @@ -220,15 +222,15 @@ def test_storage_open_object_multiple_ranged_read(
)
event_loop.run_until_complete(
storage_open_object_multiple_ranged_read.storage_open_object_multiple_ranged_read(
_ZONAL_BUCKET, object_name, grpc_client=async_grpc_client
_RAPID_BUCKET, object_name, grpc_client=async_grpc_client
)
)
out, _ = capsys.readouterr()
assert "Downloaded 10 bytes into buffer 1 from start byte 0: b'aaaaaaaaaa'" in out
assert "Downloaded 10 bytes into buffer 2 from start byte 20: b'aaaaaaaaaa'" in out
assert "Downloaded 10 bytes into buffer 3 from start byte 40: b'aaaaaaaaaa'" in out
assert "Downloaded 10 bytes into buffer 4 from start byte 60: b'aaaaaaaaaa'" in out
blob = json_client.bucket(_ZONAL_BUCKET).blob(object_name)
blob = json_client.bucket(_RAPID_BUCKET).blob(object_name)
blob.delete()


Expand All @@ -248,14 +250,14 @@ def test_storage_open_multiple_objects_ranged_read(

event_loop.run_until_complete(
storage_open_multiple_objects_ranged_read.storage_open_multiple_objects_ranged_read(
_ZONAL_BUCKET, [blob1_name, blob2_name], grpc_client=async_grpc_client
_RAPID_BUCKET, [blob1_name, blob2_name], grpc_client=async_grpc_client
)
)
out, _ = capsys.readouterr()
assert f"Downloaded {len(data1)} bytes from {blob1_name}" in out
assert f"Downloaded {len(data2)} bytes from {blob2_name}" in out
blob1 = json_client.bucket(_ZONAL_BUCKET).blob(blob1_name)
blob2 = json_client.bucket(_ZONAL_BUCKET).blob(blob2_name)
blob1 = json_client.bucket(_RAPID_BUCKET).blob(blob1_name)
blob2 = json_client.bucket(_RAPID_BUCKET).blob(blob2_name)
blob1.delete()
blob2.delete()

Expand All @@ -266,11 +268,11 @@ def test_storage_optimize_write_latency_pool(
key_prefix = f"test-writer-pool-{uuid.uuid4()}"
event_loop.run_until_complete(
storage_optimize_write_latency_pool.storage_optimize_write_latency_pool(
_ZONAL_BUCKET, key_prefix, pool_size=3, grpc_client=async_grpc_client
_RAPID_BUCKET, key_prefix, pool_size=3, grpc_client=async_grpc_client
)
)
out, _ = capsys.readouterr()
assert f"Read unfinalized object {key_prefix}_0: 0123456789" in out
bucket = json_client.bucket(_ZONAL_BUCKET)
bucket = json_client.bucket(_RAPID_BUCKET)
for i in range(4):
bucket.blob(f"{key_prefix}_{i}").delete()
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
async def storage_create_and_write_appendable_object(
bucket_name, object_name, grpc_client=None
):
"""Uploads an appendable object to zonal bucket.
"""Uploads an appendable object to rapid bucket.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Per official Cloud Storage terminology (and Go's storage/bidi/ samples), "Rapid Bucket" is the product name while the bucket requirement is "a bucket with the Rapid storage class". This also fixes the missing article ("to rapid bucket"). Please also run black on this file to remove the extra blank lines around lines 27–28 and 36.

Suggested change
"""Uploads an appendable object to rapid bucket.
"""Uploads an appendable object to a bucket with the Rapid storage class.


grpc_client: an existing grpc_client to use, this is only for testing.
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

"""Downloads a range of bytes from multiple objects concurrently.
Example usage:
```python samples/snippets/zonal_buckets/storage_open_multiple_objects_ranged_read.py \
```python samples/snippets/bidi/storage_open_multiple_objects_ranged_read.py \
--bucket_name <BUCKET_NAME> \
--object_names <OBJECT_1> <OBJECT_2> <OBJECT_3>```
"""
Comment on lines 17 to 22

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Update the example path to work from the repository root, remove the markdown backticks (which print literally in --help), and add a blank line after the module docstring to satisfy black.

Suggested change
"""Downloads a range of bytes from multiple objects concurrently.
Example usage:
```python samples/snippets/zonal_buckets/storage_open_multiple_objects_ranged_read.py \
```python samples/snippets/bidi/storage_open_multiple_objects_ranged_read.py \
--bucket_name <BUCKET_NAME> \
--object_names <OBJECT_1> <OBJECT_2> <OBJECT_3>```
"""
"""Downloads a range of bytes from multiple objects concurrently.
Example usage:
python storage/samples/snippets/bidi/storage_open_multiple_objects_ranged_read.py \
--bucket_name <BUCKET_NAME> \
--object_names <OBJECT_1> <OBJECT_2> <OBJECT_3>
"""

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@
async def storage_optimize_write_latency_pool(
bucket_name: str, key_prefix: str, pool_size: int = 3, grpc_client=None
):
"""Uses a pre-warmed pool of writers for a zonal bucket.
"""Uses a pre-warmed pool of writers for appendable objects in a rapid bucket.

grpc_client: an existing grpc_client to use, this is only for testing.
"""
# The ID of your GCS zonal bucket
# The ID of your GCS rapid bucket
# bucket_name = "your-unique-bucket-name"
Comment on lines +35 to 40

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Use "a bucket with the Rapid storage class" instead of "a rapid bucket" to match Cloud Storage terminology and Go's optimize_write_latency_pool.go. Note that line 39 is inside the region tag and renders in public docs.

Suggested change
"""Uses a pre-warmed pool of writers for appendable objects in a rapid bucket.
grpc_client: an existing grpc_client to use, this is only for testing.
"""
# The ID of your GCS zonal bucket
# The ID of your GCS rapid bucket
# bucket_name = "your-unique-bucket-name"
"""Uses a pre-warmed pool of writers for appendable objects in a bucket with the Rapid storage class.
grpc_client: an existing grpc_client to use, this is only for testing.
"""
# The ID of your GCS bucket (must use the Rapid storage class)
# bucket_name = "your-unique-bucket-name"


# The prefix for your pooled GCS objects
Expand Down Expand Up @@ -117,7 +117,7 @@ async def maintain_pool(
formatter_class=argparse.RawDescriptionHelpFormatter,
)
parser.add_argument(
"--bucket_name", help="Your Cloud Storage zonal bucket name."
"--bucket_name", help="Your Cloud Storage rapid bucket name."
)
Comment on lines 119 to 121

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Update the --bucket_name help text to use "Rapid storage class" wording. Please also run black on this file so CI does not reformat lines 64–70 and 122–124.

Suggested change
parser.add_argument(
"--bucket_name", help="Your Cloud Storage zonal bucket name."
"--bucket_name", help="Your Cloud Storage rapid bucket name."
)
parser.add_argument(
"--bucket_name",
help="Your Cloud Storage bucket name (must use the Rapid storage class).",
)

parser.add_argument(
"--key_prefix", help="Prefix for pooled object names."
Expand Down

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[Blocking — Fixes Lint CI] (lines 17–21): flake8-import-order (--import-order-style=google) requires standard library imports to be sorted alphabetically by module name. Both datetime and io must appear before time.

import argparse
import asyncio
from datetime import datetime
from io import BytesIO
import time

File renamed without changes.
Loading
Loading