From 89e4e4782f709bc2425846686c506e45fcbbfe50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Thu, 1 Jun 2023 14:13:09 +0200 Subject: [PATCH 1/2] feat: make administrative request retries optional Make retries of administrative requests that fail because the administrative request limit has been exceeded optional. This allows users to apply custom retries or other custom handling for these errors. --- .../google/cloud/spanner/SpannerOptions.java | 15 ++++++++++- .../spanner/DatabaseAdminClientTest.java | 27 +++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java index 6663d3f8e68..33fa826bfec 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java @@ -993,13 +993,26 @@ public Builder setAutoThrottleAdministrativeRequests() { return this; } + /** + * Disables automatic retries of administrative requests that fail if the https://cloud.google.com/spanner/quotas#administrative_limits + * have been exceeded. You should disable these retries if you intend to handle these errors in + * your application. + */ + public Builder disableAdministrativeRequestRetries() { + this.retryAdministrativeRequestsSettings = + this.retryAdministrativeRequestsSettings.toBuilder().setMaxAttempts(1).build(); + return this; + } + /** * Sets the retry settings for retrying administrative requests when the quote of administrative * requests per minute has been exceeded. */ Builder setRetryAdministrativeRequestsSettings( RetrySettings retryAdministrativeRequestsSettings) { - this.retryAdministrativeRequestsSettings = retryAdministrativeRequestsSettings; + this.retryAdministrativeRequestsSettings = + Preconditions.checkNotNull(retryAdministrativeRequestsSettings); return this; } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientTest.java index eee9f520a7d..5ef7b508049 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientTest.java @@ -935,4 +935,31 @@ public void testRetryOperationOnAdminMethodQuotaPerMinutePerProjectExceeded() { assertEquals(DB_ID, database.getId().getDatabase()); assertEquals(2, mockDatabaseAdmin.countRequestsOfType(GetDatabaseRequest.class)); } + + @Test + public void testRetriesDisabledForOperationOnAdminMethodQuotaPerMinutePerProjectExceeded() { + ErrorInfo info = + ErrorInfo.newBuilder() + .putMetadata("quota_limit", "AdminMethodQuotaPerMinutePerProject") + .build(); + Metadata.Key key = + Metadata.Key.of( + info.getDescriptorForType().getFullName() + Metadata.BINARY_HEADER_SUFFIX, + ProtoLiteUtils.metadataMarshaller(info)); + Metadata trailers = new Metadata(); + trailers.put(key, info); + mockDatabaseAdmin.addException( + Status.RESOURCE_EXHAUSTED.withDescription("foo").asRuntimeException(trailers)); + mockDatabaseAdmin.clearRequests(); + + Spanner spannerWithoutRetries = + spanner.getOptions().toBuilder().disableAdministrativeRequestRetries().build().getService(); + AdminRequestsPerMinuteExceededException exception = + assertThrows( + AdminRequestsPerMinuteExceededException.class, + () -> spannerWithoutRetries.getDatabaseAdminClient().getDatabase(INSTANCE_ID, DB_ID)); + assertEquals(ErrorCode.RESOURCE_EXHAUSTED, exception.getErrorCode()); + // There should be only one request on the server, as the request was not retried. + assertEquals(1, mockDatabaseAdmin.countRequestsOfType(GetDatabaseRequest.class)); + } } From 872caffb34b56941b406710d96dc144d829c41f4 Mon Sep 17 00:00:00 2001 From: Owl Bot Date: Thu, 1 Jun 2023 12:18:42 +0000 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=A6=89=20Updates=20from=20OwlBot=20po?= =?UTF-8?q?st-processor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e38127306f9..7042c600b79 100644 --- a/README.md +++ b/README.md @@ -57,13 +57,13 @@ implementation 'com.google.cloud:google-cloud-spanner' If you are using Gradle without BOM, add this to your dependencies: ```Groovy -implementation 'com.google.cloud:google-cloud-spanner:6.42.2' +implementation 'com.google.cloud:google-cloud-spanner:6.42.3' ``` If you are using SBT, add this to your dependencies: ```Scala -libraryDependencies += "com.google.cloud" % "google-cloud-spanner" % "6.42.2" +libraryDependencies += "com.google.cloud" % "google-cloud-spanner" % "6.42.3" ``` @@ -412,7 +412,7 @@ Java is a registered trademark of Oracle and/or its affiliates. [kokoro-badge-link-5]: http://storage.googleapis.com/cloud-devrel-public/java/badges/java-spanner/java11.html [stability-image]: https://img.shields.io/badge/stability-stable-green [maven-version-image]: https://img.shields.io/maven-central/v/com.google.cloud/google-cloud-spanner.svg -[maven-version-link]: https://central.sonatype.com/artifact/com.google.cloud/google-cloud-spanner/6.42.2 +[maven-version-link]: https://central.sonatype.com/artifact/com.google.cloud/google-cloud-spanner/6.42.3 [authentication]: https://github.com/googleapis/google-cloud-java#authentication [auth-scopes]: https://developers.google.com/identity/protocols/oauth2/scopes [predefined-iam-roles]: https://cloud.google.com/iam/docs/understanding-roles#predefined_roles