From 488db15663baaf777a0bca4fa54ca5d9500084da Mon Sep 17 00:00:00 2001 From: Rahul Yadav Date: Tue, 18 Oct 2022 11:43:25 +0530 Subject: [PATCH 1/3] fix: retry on RST_STREAM internal error --- .../spanner/IsRetryableInternalError.java | 4 ++ .../spanner/IsRetryableInternalErrorTest.java | 12 ++++++ .../PartitionedDmlTransactionTest.java | 39 +++++++++++++++++++ 3 files changed, 55 insertions(+) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/IsRetryableInternalError.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/IsRetryableInternalError.java index c62b4a2e06e..d250c0ad6c4 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/IsRetryableInternalError.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/IsRetryableInternalError.java @@ -29,6 +29,8 @@ public class IsRetryableInternalError implements Predicate { private static final String EOS_ERROR_MESSAGE = "Received unexpected EOS on DATA frame from server"; + private static final String RST_STREAM_ERROR_MESSAGE = "stream terminated by RST_STREAM"; + @Override public boolean apply(Throwable cause) { if (isInternalError(cause)) { @@ -38,6 +40,8 @@ public boolean apply(Throwable cause) { return true; } else if (cause.getMessage().contains(EOS_ERROR_MESSAGE)) { return true; + } else if (cause.getMessage().contains(RST_STREAM_ERROR_MESSAGE)) { + return true; } } return false; diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IsRetryableInternalErrorTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IsRetryableInternalErrorTest.java index e1c360da74f..366b80a7513 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IsRetryableInternalErrorTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IsRetryableInternalErrorTest.java @@ -114,6 +114,18 @@ public void genericInternalStatusRuntimeExceptionIsRetryable() { assertThat(predicate.apply(e)).isFalse(); } + @Test + public void rstStreamInternalExceptionIsRetryable() { + final InternalException e = + new InternalException( + "INTERNAL: stream terminated by RST_STREAM.", + null, + GrpcStatusCode.of(Code.INTERNAL), + false); + + assertThat(predicate.apply(e)).isTrue(); + } + @Test public void genericInternalExceptionIsNotRetryable() { final InternalException e = diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/PartitionedDmlTransactionTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/PartitionedDmlTransactionTest.java index 61dcef2902a..de1ec8fa39e 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/PartitionedDmlTransactionTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/PartitionedDmlTransactionTest.java @@ -344,6 +344,45 @@ public void testExecuteStreamingPartitionedUpdateUnexpectedEOS() { Mockito.eq(executeRequestWithResumeToken), anyMap(), any(Duration.class)); } + @Test + public void testExecuteStreamingPartitionedUpdateRSTstream() { + ResultSetStats stats = ResultSetStats.newBuilder().setRowCountLowerBound(1000L).build(); + PartialResultSet p1 = PartialResultSet.newBuilder().setResumeToken(resumeToken).build(); + PartialResultSet p2 = PartialResultSet.newBuilder().setStats(stats).build(); + ServerStream stream1 = mock(ServerStream.class); + Iterator iterator = mock(Iterator.class); + when(iterator.hasNext()).thenReturn(true, true, false); + when(iterator.next()) + .thenReturn(p1) + .thenThrow( + new InternalException( + "INTERNAL: stream terminated by RST_STREAM.", + null, + GrpcStatusCode.of(Code.INTERNAL), + true)); + when(stream1.iterator()).thenReturn(iterator); + ServerStream stream2 = mock(ServerStream.class); + when(stream2.iterator()).thenReturn(ImmutableList.of(p1, p2).iterator()); + when(rpc.executeStreamingPartitionedDml( + Mockito.eq(executeRequestWithoutResumeToken), anyMap(), any(Duration.class))) + .thenReturn(stream1); + when(rpc.executeStreamingPartitionedDml( + Mockito.eq(executeRequestWithResumeToken), anyMap(), any(Duration.class))) + .thenReturn(stream2); + + PartitionedDmlTransaction tx = new PartitionedDmlTransaction(session, rpc, ticker); + long count = tx.executeStreamingPartitionedUpdate(Statement.of(sql), Duration.ofMinutes(10)); + + assertThat(count).isEqualTo(1000L); + verify(rpc).beginTransaction(any(BeginTransactionRequest.class), anyMap()); + verify(rpc) + .executeStreamingPartitionedDml( + Mockito.eq(executeRequestWithoutResumeToken), anyMap(), any(Duration.class)); + verify(rpc) + .executeStreamingPartitionedDml( + Mockito.eq(executeRequestWithResumeToken), anyMap(), any(Duration.class)); + } + @Test public void testExecuteStreamingPartitionedUpdateGenericInternalException() { PartialResultSet p1 = PartialResultSet.newBuilder().setResumeToken(resumeToken).build(); From c7344c027f39ff0c9e38642852520f5788a7e093 Mon Sep 17 00:00:00 2001 From: rahul2393 Date: Wed, 9 Nov 2022 10:52:26 +0530 Subject: [PATCH 2/3] Update google-cloud-spanner/src/test/java/com/google/cloud/spanner/IsRetryableInternalErrorTest.java MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Knut Olav Løite --- .../com/google/cloud/spanner/IsRetryableInternalErrorTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IsRetryableInternalErrorTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IsRetryableInternalErrorTest.java index 366b80a7513..63039fcd237 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IsRetryableInternalErrorTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IsRetryableInternalErrorTest.java @@ -17,6 +17,7 @@ package com.google.cloud.spanner; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertTrue; import com.google.api.gax.grpc.GrpcStatusCode; import com.google.api.gax.rpc.InternalException; @@ -123,7 +124,7 @@ public void rstStreamInternalExceptionIsRetryable() { GrpcStatusCode.of(Code.INTERNAL), false); - assertThat(predicate.apply(e)).isTrue(); + assertTrue(predicate.apply(e)); } @Test From 9ef8b04e091f4941372a663a06241f4803a3b65b Mon Sep 17 00:00:00 2001 From: Owl Bot Date: Tue, 10 Jan 2023 07:12:01 +0000 Subject: [PATCH 3/3] =?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 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index baac29f6974..38486eb0573 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ If you are using Maven without BOM, add this to your dependencies: If you are using Gradle 5.x or later, add this to your dependencies: ```Groovy -implementation platform('com.google.cloud:libraries-bom:26.2.0') +implementation platform('com.google.cloud:libraries-bom:26.3.0') implementation 'com.google.cloud:google-cloud-spanner' ```