From 8c3f9dd75714f3f8d45a24971b0c4e3b74e86ec9 Mon Sep 17 00:00:00 2001 From: Brent Shaffer Date: Wed, 10 Dec 2025 12:11:23 -0800 Subject: [PATCH 1/4] feat(docs): add product neutral guides --- help/.gitignore | 2 + help/.yardopts | 0 help/CLIENT_CONFIGURATION.md | 134 +++++++++++++++++ help/CORE_CONCEPTS.md | 271 +++++++++++++++++++++++++++++++++++ help/OCC_FOR_IAM.md | 100 +++++++++++++ help/TROUBLESHOOTING.md | 126 ++++++++++++++++ 6 files changed, 633 insertions(+) create mode 100644 help/.gitignore create mode 100644 help/.yardopts create mode 100644 help/CLIENT_CONFIGURATION.md create mode 100644 help/CORE_CONCEPTS.md create mode 100644 help/OCC_FOR_IAM.md create mode 100644 help/TROUBLESHOOTING.md diff --git a/help/.gitignore b/help/.gitignore new file mode 100644 index 000000000000..d7765fa46930 --- /dev/null +++ b/help/.gitignore @@ -0,0 +1,2 @@ +doc/* +.yardoc diff --git a/help/.yardopts b/help/.yardopts new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/help/CLIENT_CONFIGURATION.md b/help/CLIENT_CONFIGURATION.md new file mode 100644 index 000000000000..d7a4b237bb82 --- /dev/null +++ b/help/CLIENT_CONFIGURATION.md @@ -0,0 +1,134 @@ +# Client Configuration + +The Google Cloud Ruby Client Libraries allow you to configure client behavior via keyword arguments passed to the client constructor (or `configure` blocks). + +## 1\. Customizing the API Endpoint + +You can modify the API endpoint to connect to a specific Google Cloud region or to a private endpoint. + +### Connecting to a Regional Endpoint + +```ruby +require "google/cloud/pubsub" + +# Connect explicitly to the us-east1 region +pubsub = Google::Cloud::Pubsub.new( + endpoint: "us-east1-pubsub.googleapis.com:443" +) +``` + +## 2\. Authenticating + +## See [Authentication](https://docs.cloud.google.com/ruby/docs/reference/help/authentication) for a comprehensive guide. + +## 3\. Logging + +## See [Troubleshooting](https://docs.cloud.google.com/ruby/docs/reference/help/troubleshooting) for a comprehensive guide. + +## 4\. Configuring a Proxy + +The configuration method depends on whether the client uses gRPC (most clients) or REST (e.g., Storage, BigQuery partial). + +### Proxy with gRPC + +The Ruby gRPC layer respects standard environment variables. You generally do not configure this in the Ruby code itself. + +Set the following environment variables in your shell or Docker container: + +``` +export http_proxy="http://proxy.example.com:3128" +export https_proxy="http://proxy.example.com:3128" +``` + +**Handling Self-Signed Certificates (gRPC):** If your proxy uses a self-signed certificate, point gRPC to the CA bundle: + +``` +export GRPC_DEFAULT_SSL_ROOTS_FILE_PATH="/path/to/roots.pem" +``` + +### Proxy with REST (e.g., Google::Cloud::Storage) + +The underlying HTTP libraries in Ruby (often `Faraday` or `httpclient`) also respect the standard `http_proxy` environment variables automatically. + +However, if you must configure it in code (specifically for `Google::Cloud::Storage`), you can pass connection options: + +```ruby +require "google/cloud/storage" + +storage = Google::Cloud::Storage.new( + connection_options: { + proxy: "http://user:password@proxy.example.com" + } +) +``` + +## 5\. Configuring Retries and Timeouts + +Ruby uses **Seconds** (Float/Integer) for time values, whereas PHP uses Milliseconds. + +### Per-Call Configuration (Recommended) + +You can override settings for specific calls using keyword arguments (`retry_policy` and `timeout`). + +```ruby +require "google/cloud/secret_manager" + +# Instantiate the client +# Note: secret_manager_service gives access to the V1 GAPIC client +client = Google::Cloud::SecretManager.secret_manager_service + +# Prepare the request +parent = "projects/my-project" + +# Advanced Retry Configuration +# Note: Time values are in SECONDS +retry_policy = { + initial_delay: 0.5, # Start with 0.5s wait + max_delay: 5.0, # Cap wait at 5s + multiplier: 2.0, # Double the wait each time + retry_codes: [14] # Retry on specific gRPC error codes (e.g., UNAVAILABLE) +} + +# Make the call +client.list_secrets( + parent: parent, + retry_policy: retry_policy, + timeout: 15.0 # Max 15s total (Total Timeout) +) +``` + +### Available `retry_policy` Keys + +| Key | Type | Description | +| ----- | ----- | ----- | +| `initial_delay` | Float | Wait time before the first retry (in **seconds**). | +| `max_delay` | Float | The maximum wait time between any two retries (in **seconds**). | +| `multiplier` | Float | Multiplier applied to the delay after each failure. | +| `retry_codes` | Array | List of gRPC error codes (integers) that should trigger a retry. | + +### Global Client Configuration + +You can configure defaults globally when initializing the low-level GAPIC client, though per-call is preferred for specific logic. + +```php +require "google/cloud/pubsub" + +# Create a client with a custom timeout for all requests +pubsub = Google::Cloud::Pubsub.new( + timeout: 10 # Default 10 seconds for all operations +) +``` + +## 6\. Other Common Configuration Options + +The following options can be passed to the constructor of generated clients (e.g., `Google::Cloud::Pubsub`, `Google::Cloud::Spanner`, `Google::Cloud::Storage`). + +| Option Key | Type | Description | +| ----- | ----- | ----- | +| `credentials` | String / Hash | Path to the JSON keyfile or the JSON object itself. | +| `endpoint` | String | The address of the API remote host. Used for Regional Endpoints (e.g., `us-central1-pubsub.googleapis.com:443`). | +| `lib_name` / `lib_version` | String | Used to append identification to the `x-goog-api-client` header for tracing/debugging. | +| `timeout` | Numeric | The default timeout (in **seconds**) for requests. | +| `retries` | Integer | Number of retries for the underlying HTTP/gRPC connection (distinct from logic retries). | +| `project_id` | String | Explicitly sets the project ID, overriding environment variables. | +| `universe_domain` | String | Overrides the default service domain (defaults to `googleapis.com`) for Cloud Universe support. | diff --git a/help/CORE_CONCEPTS.md b/help/CORE_CONCEPTS.md new file mode 100644 index 000000000000..f63c55eceb82 --- /dev/null +++ b/help/CORE_CONCEPTS.md @@ -0,0 +1,271 @@ +# Core Concepts + +This documentation covers essential patterns and usage for the Google Cloud Ruby Client Library, focusing on performance (gRPC), data handling (Protobuf, Update Masks), and flow control (Pagination, LROs, Streaming). + +## 1\. Pagination + +Most list methods in the Google Cloud Ruby library return a `Gapic::PagedEnumerable`. This allows you to iterate over results without manually managing page tokens. + +The easiest way to handle pagination is to simply `.each` over the response. The library automatically fetches new pages in the background as you iterate. + +```ruby +require "google/cloud/secret_manager" + +# Initialize the client +client = Google::Cloud::SecretManager.secret_manager_service + +# Call the API using keyword arguments +# Returns a Gapic::PagedEnumerable +response = client.list_secrets parent: "projects/my-project" + +# Automatically fetches subsequent pages of secrets +response.each do |secret| + puts "Secret: #{secret.name}" +end +``` + +### Manual Pagination (Using Page Tokens) + +If you need to control pagination manually (e.g., for a web API), you can access the `next_page_token` and the page object. + +```ruby +# Call with page_size +response = client.list_secrets parent: "projects/my-project", page_size: 10 + +# Process current page items +response.response.secrets.each do |secret| + # Process logic +end + +# Check for next page +if response.next_page? + next_token = response.next_page_token + # Pass this token to the next call: + # client.list_secrets(..., page_token: next_token) +end +``` + +## 2\. Long Running Operations (LROs) + +Some operations return a Long Running Operation (LRO). The Ruby library provides a wrapper (often `Gapic::Operation`) to manage these. + +### Polling for Completion + +The standard pattern is to call `wait_until_done!`. + +```ruby +require "google/cloud/compute/v1" + +instances_client = Google::Cloud::Compute::V1::Instances::Client.new + +# Prepare the request arguments +instance_resource = { + name: "new-instance", + machine_type: "zones/us-central1-a/machineTypes/n1-standard-1" + # ... other fields +} + +# Call the method +operation = instances_client.insert project: project, zone: zone, instance_resource: instance_resource + +# Wait for the operation to complete +# This blocks the script, polling periodically +operation.wait_until_done! + +if operation.error? + puts "Error: #{operation.error.message}" +else + # Get the result resource + result = operation.response + puts "Instance created: #{result.name}" +end +``` + +### Async / Non-Blocking Check + +If you don't want to block the script, you can store the Operation Name. + +```ruby +# 1. Start operation +operation = client.long_running_method(...) +op_name = operation.name + +# ... later, or in a different worker process ... + +# 2. Retrieve operation status +# Note: You usually use a specific Operations Client or the main client's operations helper +# For specific services, it might look like: +checked_op = client.get_operation name: op_name + +if checked_op.done? + # Handle success +end +``` + +## 3\. Update Masks + +When updating resources (PATCH requests), you use a `Google::Protobuf::FieldMask`. Ruby clients often provide helpers, or you can construct the mask explicitly. + +### Constructing a FieldMask + +```ruby +require "google/cloud/secret_manager" + +client = Google::Cloud::SecretManager.secret_manager_service + +# 1. Prepare the resource with NEW values +# In Ruby, we often use a Hash or the Protobuf object directly +secret = { + name: "projects/my-project/secrets/my-secret", + labels: { "env" => "production" } # We only want to update this field +} + +# 2. Create the FieldMask +# 'paths' MUST match the protobuf field names (snake_case) +update_mask = { paths: ["labels"] } + +# 3. Call the API +# Ruby arguments match the proto definition +client.update_secret secret: secret, update_mask: update_mask +``` + +## 4\. Protobuf and gRPC + +The Google Cloud Ruby library supports two transports: REST (HTTP/1.1) and gRPC. + +* **Protobuf (Protocol Buffers):** The mechanism for serializing structured data. Ruby uses the `google-protobuf` gem. +* **gRPC:** The high-performance RPC framework. Ruby uses the `grpc` gem. + +### Installation & Setup + +Unlike PHP (which requires PECL), Ruby handles these extensions via Gems. If you are using `google-cloud-*` gems, these dependencies are usually installed automatically. + +**Gemfile:** + +```ruby +gem "google-cloud-pubsub" +# The following are usually pulled in automatically, but can be explicit: +# gem "grpc" +# gem "google-protobuf" +``` + +**Terminal:** + +``` +bundle install +``` + +### Usage in Client + +The client library uses gRPC by default if the gem is available. You can force a specific transport using the `transport` keyword argument (usually handled at the GAPIC layer). + +```ruby +require "google/cloud/pubsub" + +# Force REST transport (if supported by the specific client) +# Note: Most modern Ruby clients default to gRPC automatically. +publisher = Google::Cloud::Pubsub::V1::Publisher::Client.new do |config| + config.transport = :grpc # or :rest +end +``` + +## 5\. gRPC Streaming + +gRPC Streaming allows continuous data flow. + +| Type | Description | Common Ruby Use Case | +| ----- | ----- | ----- | +| **Server-Side** | Client sends one request; Server streams messages. | Reading BigQuery rows, watching logs. | +| **Client-Side** | Client streams messages; Server waits for close. | Asynchronous speech recognition, bulk uploads. | +| **Bidirectional** | Both stream messages independently. | Real-time Speech-to-Text. | + +### Server-Side Streaming Example + +This behaves like a standard Ruby Enumerable. + +```ruby +require "google/cloud/bigquery/storage" + +read_client = Google::Cloud::Bigquery::Storage.bigquery_read_service + +# Prepare request +read_stream_name = "projects/my-proj/locations/us/sessions/id/streams/id" + +# read_rows returns an Enumerable +stream = read_client.read_rows read_stream: read_stream_name + +# Iterate over the stream +stream.each do |response| + # response is a ReadRowsResponse object + row_data = response.avro_rows.serialized_binary_rows + puts "Row size: #{row_data.bytesize} bytes" +end +``` + +### gRPC Bidirectional Streaming + +**Crucial Difference:** unlike PHP's imperative `write()` / `read()` loop, Ruby utilizes **Enumerators**. You pass an *Input Enumerator* (containing your requests) to the method, and the method returns an *Output Enumerator* (containing the server responses). + +#### Concept: + +```ruby +# 1. Create an Enumerator that yields requests +input_stream = Enumerator.new do |yielder| + yielder << request_object_1 + yielder << request_object_2 +end + +# 2. Pass the input stream to the client +responses = client.bidi_stream_method(input_stream) + +# 3. Iterate over responses +responses.each do |response| + puts response +end +``` + +#### Real World Example: Speech-to-Text + +```ruby +require "google/cloud/speech/v2" + +client = Google::Cloud::Speech::V2::Speech::Client.new + +# Define the Input Stream (Requests) +# In a real app, this might pull from a queue or microphone buffer +request_stream = Enumerator.new do |yielder| + + # 1. First Yield: Configuration + recognition_config = { + explicit_decoding_config: { + encoding: :LINEAR16, + sample_rate_hertz: 16000, + audio_channel_count: 1 + } + } + + streaming_config = { config: recognition_config } + + yielder << { recognizer: "projects/.../recognizers/...", streaming_config: streaming_config } + + # 2. Subsequent Yields: Audio Data + # Simulating reading chunks + File.open("audio.raw", "rb") do |file| + while chunk = file.read(4096) + yielder << { audio: chunk } + end + end +end + +# Call the API +# We pass the Enumerator into the method +responses = client.streaming_recognize request_stream + +# Iterate over responses as they arrive +responses.each do |response| + response.results.each do |result| + puts "Transcript: #{result.alternatives[0].transcript}" + end +end +``` + diff --git a/help/OCC_FOR_IAM.md b/help/OCC_FOR_IAM.md new file mode 100644 index 000000000000..1c47d0334f64 --- /dev/null +++ b/help/OCC_FOR_IAM.md @@ -0,0 +1,100 @@ +# Optimistic Concurrency Control (OCC) Loop for IAM + +## Introduction to OCC + +Optimistic Concurrency Control (OCC) is a strategy used to manage shared resources and prevent "lost updates" or race conditions when multiple users or processes attempt to modify the same resource simultaneously. + +In the context of Google Cloud IAM, the resource is the IAM Policy applied to a resource (like a Project, Bucket, or Service). An IAM Policy object contains a version number and an **etag** (entity tag) field. + +OCC introduces a unique fingerprint (etag) which changes every time an entity is modified. The IAM service checks this tag on every write: + +1. When you **read** the policy, the server returns an etag. +2. When you **write** the modified policy, you must include that original etag. +3. If the server finds the etag provided does not match the current stored etag, the write fails with an `ABORTED` or `FAILED_PRECONDITION` error. + +This failure forces the client to retry the entire process—re-read, re-apply changes, and re-write. + +## Implementing the OCC Loop + +The core of the implementation is a loop that handles the retry logic. We use Ruby's `begin ... rescue` block to catch specific concurrency errors. + +### Steps of the Loop + +| Step | Action | Ruby Implementation | +| ----- | ----- | ----- | +| **1\. Read** | Fetch the current IAM Policy. | `policy = client.get_iam_policy resource: name` | +| **2\. Modify** | Apply changes to the local policy object. | `policy.bindings << new_binding` | +| **3\. Write** | Attempt to set the modified policy. | `client.set_iam_policy resource: name, policy: policy` | +| **4\. Retry** | Catch errors and loop. | `rescue Google::Cloud::AbortedError` | + +## Example + +The following example demonstrates how to implement the OCC loop using the `google-cloud-resource_manager-v3` gem. + +```ruby +require "google/cloud/resource_manager/v3" + +# Executes an Optimistic Concurrency Control (OCC) loop to safely update an IAM policy. +# +# @param project_id [String] The Google Cloud Project ID (e.g., 'my-project-123'). +# @param role [String] The IAM role to grant (e.g., 'roles/storage.objectAdmin'). +# @param member [String] The member to add (e.g., 'user:user@example.com'). +# @param max_retries [Integer] Maximum number of retries. +def update_iam_policy_with_occ(project_id, role, member, max_retries = 5) + # 1. Setup Client + client = Google::Cloud::ResourceManager::V3::Projects::Client.new + project_name = "projects/#{project_id}" + + retries = 0 + + # --- START OCC LOOP --- + begin + # 2. READ: Get current policy (includes etag) + puts "Attempt #{retries + 1}: Reading policy for #{project_name}..." + policy = client.get_iam_policy resource: project_name + + # 3. MODIFY: Apply changes locally + # Find existing binding for the role, or create a new one + binding = policy.bindings.find { |b| b.role == role } + + if binding + # If the member isn't already there, add them + unless binding.members.include?(member) + binding.members << member + end + else + # Create new binding + new_binding = Google::Iam::V1::Binding.new( + role: role, + members: [member] + ) + policy.bindings << new_binding + end + + # 4. WRITE: Attempt to update + # The policy object contains the 'etag' from the READ step. + puts "Attempt #{retries + 1}: Writing modified policy..." + client.set_iam_policy resource: project_name, policy: policy + + puts "Successfully updated IAM policy." + return policy + + rescue Google::Cloud::AbortedError, Google::Cloud::FailedPreconditionError => e + # 5. RETRY LOGIC + retries += 1 + if retries < max_retries + puts "Concurrency conflict (etag mismatch). Retrying... (#{retries}/#{max_retries})" + sleep(0.1 * retries) # Exponential backoff + retry # Restarts the `begin` block + else + puts "Failed to update policy after #{max_retries} attempts." + raise e + end + end + # --- END OCC LOOP --- +end + +# Usage Example: +# update_iam_policy_with_occ("my-project-id", "roles/viewer", "user:test@example.com") +``` + diff --git a/help/TROUBLESHOOTING.md b/help/TROUBLESHOOTING.md new file mode 100644 index 000000000000..76b149a268ef --- /dev/null +++ b/help/TROUBLESHOOTING.md @@ -0,0 +1,126 @@ +# Troubleshooting + +## Debug Logging + +There are features built into the Google Cloud Ruby client libraries which can help you debug your application. This guide will show you how to log client library requests and responses. + +**Warning:** These logs are not intended to be used in production and are meant to be used only for quickly debugging a project. The logs consist of basic logging to STDOUT, which may or may not include sensitive information. Make sure that once you are done debugging to disable the debugging flag or configuration used to avoid leaking sensitive user data. This may also include authentication tokens. + +### Log examples + +In Ruby, you typically pass a standard Ruby `Logger` instance to the client. + +```ruby +# debug_logging_example.rb +require "google/cloud/translate/v3" +require "logger" + +# Create a logger that outputs to STDOUT with DEBUG level +logger = Logger.new(STDOUT) +logger.level = Logger::DEBUG + +# Pass the logger to the client +client = Google::Cloud::Translate::V3::TranslationService::Client.new do |config| + config.logger = logger +end + +request = { + parent: "projects/my-project", + target_language_code: "en-US", + contents: ["こんにちは"] +} + +# The request and response will be logged to STDOUT +response = client.translate_text request +``` + +Running this script will output detailed debug information from the client library. + +## Configuration + +There are a few ways to configure debug logging which we will go through in this document. + +### Passing a Standard Ruby Logger + +The Ruby client libraries are designed to accept any logger that matches the interface of the standard Ruby `Logger` class. + +```ruby +require "logger" + +# Create a customized logger +custom_logger = Logger.new("application.log") +custom_logger.level = Logger::DEBUG + +client = Google::Cloud::Translate::V3::TranslationService::Client.new do |config| + config.logger = custom_logger +end +``` + +With this, you will be using your custom logger implementation. This opens the opportunity to extend the capabilities of logging in case you have specific needs (e.g., log rotation, formatting). + +### Global Configuration + +You can also configure the logger globally for all Google Cloud clients in your application using `Google::Cloud::Configure`. + +```ruby +require "google/cloud/translate/v3" + +Google::Cloud.configure do |config| + config.logger = Logger.new(STDERR) + config.logger.level = Logger::WARN +end + +# This client will automatically use the global logger configuration +client = Google::Cloud::Translate::V3::TranslationService::Client.new +``` + +### Disabling Logging + +To ensure a client does not log, you can pass a generic logger that does nothing, or simply ensure the log level is set high enough (e.g., `FATAL`) that normal operations are not recorded. + +```ruby +# The TranslationServiceClient will not log debug/info messages +client = Google::Cloud::Translate::V3::TranslationService::Client.new do |config| + # Use a logger that discards output or has a high threshold + config.logger = Logger.new(nil) +end +``` + +## How can I trace gRPC issues? + +When working with libraries that use gRPC (which is the default transport for many Google Cloud Ruby clients), you can use the underlying gRPC C-core environment variables to enable logging. + +### Prerequisites + +Ensure you have the `grpc` gem installed. You can check this by running: + +```ruby +gem list grpc +# or if using bundler +bundle show grpc +``` + +### Transport logging with gRPC + +The primary method for debugging gRPC calls in Ruby is setting environment variables. These affect the underlying C extension. The environment variables affecting gRPC are listed in the [gRPC repository](https://www.google.com/search?q=https://github.com/grpc/grpc/blob/master/doc/environment_variables.md). The important ones for diagnostics are `GRPC_TRACE` and `GRPC_VERBOSITY`. + +For example, you might want to start off with `GRPC_TRACE=all` and `GRPC_VERBOSITY=debug` which will dump a lot of information, then tweak them to reduce this to only useful data (e.g., `GRPC_TRACE=http,call_error`). + +``` +GRPC_VERBOSITY=debug GRPC_TRACE=all ruby your_script.rb +``` + +## How can I diagnose proxy issues? + +See [**Client Configuration**: Configuring a Proxy](https://docs.cloud.google.com/ruby/docs/reference/help/client_configuration). + +## Reporting a problem + +If none of the above advice helps to resolve your issue, please ask for help. If you have a support contract with Google, please create an issue in the support console instead of filing on GitHub. This will ensure a timely response. + +Otherwise, please either file an issue on GitHub or ask a question on Stack Overflow. In most cases creating a GitHub issue will result in a quicker turnaround time, but if you believe your question is likely to help other users in the future, Stack Overflow is a good option. When creating a Stack Overflow question, please use the `google-cloud-platform` tag and `ruby` tag. + +Although there are multiple GitHub repositories associated with the Google Cloud Libraries, we recommend filing an issue in [https://github.com/googleapis/google-cloud-ruby](https://github.com/googleapis/google-cloud-ruby) unless you are certain that it belongs elsewhere. The maintainers may move it to a different repository where appropriate, but you will be notified of this via the email associated with your GitHub account. + +When filing an issue or asking a Stack Overflow question, please include as much of the following information as possible. This will enable us to help you quickly. + From 8404a70f83726bb36408d413b7d93a4e9c177a70 Mon Sep 17 00:00:00 2001 From: Brent Shaffer Date: Wed, 10 Dec 2025 13:07:41 -0800 Subject: [PATCH 2/4] add empty gemspec for help --- help/help.gemspec | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 help/help.gemspec diff --git a/help/help.gemspec b/help/help.gemspec new file mode 100644 index 000000000000..a9777216fe5b --- /dev/null +++ b/help/help.gemspec @@ -0,0 +1,5 @@ +# -*- encoding: utf-8 -*- +Gem::Specification.new do |gem| + gem.name = "help" + gem.version = "0.0.0" +end From c91497c1e17a17cf46f48ac38a94e1a2c9ea2be7 Mon Sep 17 00:00:00 2001 From: Brent Shaffer Date: Fri, 12 Dec 2025 07:19:15 -0800 Subject: [PATCH 3/4] fix retries sample --- help/CLIENT_CONFIGURATION.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/help/CLIENT_CONFIGURATION.md b/help/CLIENT_CONFIGURATION.md index d7a4b237bb82..fe81b044dcb3 100644 --- a/help/CLIENT_CONFIGURATION.md +++ b/help/CLIENT_CONFIGURATION.md @@ -2,7 +2,7 @@ The Google Cloud Ruby Client Libraries allow you to configure client behavior via keyword arguments passed to the client constructor (or `configure` blocks). -## 1\. Customizing the API Endpoint +## 1. Customizing the API Endpoint You can modify the API endpoint to connect to a specific Google Cloud region or to a private endpoint. @@ -17,15 +17,15 @@ pubsub = Google::Cloud::Pubsub.new( ) ``` -## 2\. Authenticating +## 2. Authenticating ## See [Authentication](https://docs.cloud.google.com/ruby/docs/reference/help/authentication) for a comprehensive guide. -## 3\. Logging +## 3. Logging ## See [Troubleshooting](https://docs.cloud.google.com/ruby/docs/reference/help/troubleshooting) for a comprehensive guide. -## 4\. Configuring a Proxy +## 4. Configuring a Proxy The configuration method depends on whether the client uses gRPC (most clients) or REST (e.g., Storage, BigQuery partial). @@ -62,7 +62,7 @@ storage = Google::Cloud::Storage.new( ) ``` -## 5\. Configuring Retries and Timeouts +## 5. Configuring Retries and Timeouts Ruby uses **Seconds** (Float/Integer) for time values, whereas PHP uses Milliseconds. @@ -90,11 +90,12 @@ retry_policy = { } # Make the call -client.list_secrets( - parent: parent, +request = { parent: parent } +options = Gapic::CallOptions.new( retry_policy: retry_policy, - timeout: 15.0 # Max 15s total (Total Timeout) + timeout: 15.0 ) +client.list_secrets request, options ``` ### Available `retry_policy` Keys @@ -119,7 +120,7 @@ pubsub = Google::Cloud::Pubsub.new( ) ``` -## 6\. Other Common Configuration Options +## 6. Other Common Configuration Options The following options can be passed to the constructor of generated clients (e.g., `Google::Cloud::Pubsub`, `Google::Cloud::Spanner`, `Google::Cloud::Storage`). From 623a3e75eb5893229d6bfdd723e0adfcb279b294 Mon Sep 17 00:00:00 2001 From: Brent Shaffer Date: Fri, 12 Dec 2025 15:11:59 -0800 Subject: [PATCH 4/4] fix LRO sample --- help/CORE_CONCEPTS.md | 39 +++++++++++++++++++++++++++++---------- help/OCC_FOR_IAM.md | 8 ++++---- 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/help/CORE_CONCEPTS.md b/help/CORE_CONCEPTS.md index f63c55eceb82..6d92a2f49691 100644 --- a/help/CORE_CONCEPTS.md +++ b/help/CORE_CONCEPTS.md @@ -2,7 +2,7 @@ This documentation covers essential patterns and usage for the Google Cloud Ruby Client Library, focusing on performance (gRPC), data handling (Protobuf, Update Masks), and flow control (Pagination, LROs, Streaming). -## 1\. Pagination +## 1. Pagination Most list methods in the Google Cloud Ruby library return a `Gapic::PagedEnumerable`. This allows you to iterate over results without manually managing page tokens. @@ -45,7 +45,7 @@ if response.next_page? end ``` -## 2\. Long Running Operations (LROs) +## 2. Long Running Operations (LROs) Some operations return a Long Running Operation (LRO). The Ruby library provides a wrapper (often `Gapic::Operation`) to manage these. @@ -56,13 +56,32 @@ The standard pattern is to call `wait_until_done!`. ```ruby require "google/cloud/compute/v1" -instances_client = Google::Cloud::Compute::V1::Instances::Client.new +# Your Google Cloud project ID +project = "your-project-id" +# The zone in which to create the instance +zone = "your-zone" # e.g., "us-central1-a" + +instances_client = Google::Cloud::Compute::V1::Instances::Rest::Client.new # Prepare the request arguments instance_resource = { name: "new-instance", - machine_type: "zones/us-central1-a/machineTypes/n1-standard-1" - # ... other fields + machine_type: "zones/us-central1-a/machineTypes/n1-standard-1", + disks: [ + { + auto_delete: true, + boot: true, + initialize_params: { + source_image: "projects/debian-cloud/global/images/debian-11-bullseye-v20230306" + } + } + ], + network_interfaces: [ + { + network: "global/networks/default", + access_configs: [{ name: "External NAT", type: "ONE_TO_ONE_NAT" }] + } + ] } # Call the method @@ -102,7 +121,7 @@ if checked_op.done? end ``` -## 3\. Update Masks +## 3. Update Masks When updating resources (PATCH requests), you use a `Google::Protobuf::FieldMask`. Ruby clients often provide helpers, or you can construct the mask explicitly. @@ -129,7 +148,7 @@ update_mask = { paths: ["labels"] } client.update_secret secret: secret, update_mask: update_mask ``` -## 4\. Protobuf and gRPC +## 4. Protobuf and gRPC The Google Cloud Ruby library supports two transports: REST (HTTP/1.1) and gRPC. @@ -169,7 +188,7 @@ publisher = Google::Cloud::Pubsub::V1::Publisher::Client.new do |config| end ``` -## 5\. gRPC Streaming +## 5. gRPC Streaming gRPC Streaming allows continuous data flow. @@ -184,9 +203,9 @@ gRPC Streaming allows continuous data flow. This behaves like a standard Ruby Enumerable. ```ruby -require "google/cloud/bigquery/storage" +require "google/cloud/bigquery/storage/v1" -read_client = Google::Cloud::Bigquery::Storage.bigquery_read_service +read_client = Google::Cloud::Bigquery::Storage::V1::BigQueryRead::Client.new # Prepare request read_stream_name = "projects/my-proj/locations/us/sessions/id/streams/id" diff --git a/help/OCC_FOR_IAM.md b/help/OCC_FOR_IAM.md index 1c47d0334f64..0669e92491d3 100644 --- a/help/OCC_FOR_IAM.md +++ b/help/OCC_FOR_IAM.md @@ -49,11 +49,11 @@ def update_iam_policy_with_occ(project_id, role, member, max_retries = 5) # --- START OCC LOOP --- begin - # 2. READ: Get current policy (includes etag) + # READ: Get current policy (includes etag) puts "Attempt #{retries + 1}: Reading policy for #{project_name}..." policy = client.get_iam_policy resource: project_name - # 3. MODIFY: Apply changes locally + # MODIFY: Apply changes locally # Find existing binding for the role, or create a new one binding = policy.bindings.find { |b| b.role == role } @@ -71,7 +71,7 @@ def update_iam_policy_with_occ(project_id, role, member, max_retries = 5) policy.bindings << new_binding end - # 4. WRITE: Attempt to update + # WRITE: Attempt to update # The policy object contains the 'etag' from the READ step. puts "Attempt #{retries + 1}: Writing modified policy..." client.set_iam_policy resource: project_name, policy: policy @@ -80,7 +80,7 @@ def update_iam_policy_with_occ(project_id, role, member, max_retries = 5) return policy rescue Google::Cloud::AbortedError, Google::Cloud::FailedPreconditionError => e - # 5. RETRY LOGIC + # RETRY LOGIC retries += 1 if retries < max_retries puts "Concurrency conflict (etag mismatch). Retrying... (#{retries}/#{max_retries})"