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 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)); + } }