Skip to content

Commit b8a031c

Browse files
authored
---
yaml --- r: 23081 b: refs/heads/autosynth-containeranalysis c: 1835cd7 h: refs/heads/master i: 23079: 4ee94c4
1 parent a6116af commit b8a031c

3 files changed

Lines changed: 61 additions & 4 deletions

File tree

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ refs/heads/autosynth-bigquerydatatransfer: d88aa5aae5fd9d3c6d75bbab1a05162c6d4d9
126126
refs/heads/autosynth-bigquerystorage: d2c53da3b012e38c662e4df0738042435f19365f
127127
refs/heads/autosynth-bigtable: 9e5429f45cf9face9fed585d0233534993e36b58
128128
refs/heads/autosynth-bigtable-admin: 6379a2bc712f2736c83de0e009b4d26da4fa82ca
129-
refs/heads/autosynth-containeranalysis: e4c11c0ebde2647f3bed5191fe4250261d828517
129+
refs/heads/autosynth-containeranalysis: 1835cd75804d3cd0632073afe747e6b6f08ba50d
130130
refs/heads/autosynth-datastore: 9acd400b484d6691a080c9152a331d88d24fefc1
131131
refs/heads/autosynth-dialogflow: 7dbc2c1ea714328ccfa4f33645045f017ff080e7
132132
refs/heads/autosynth-errorreporting: 1101a04e8be074802c35332d5fcf8297f61cae32

branches/autosynth-containeranalysis/google-cloud-clients/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerExceptionFactory.java

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,9 @@
1616

1717
package com.google.cloud.spanner;
1818

19-
import static com.google.cloud.spanner.SpannerException.DoNotConstructDirectly;
20-
2119
import com.google.api.gax.grpc.GrpcStatusCode;
2220
import com.google.api.gax.rpc.ApiException;
21+
import com.google.cloud.spanner.SpannerException.DoNotConstructDirectly;
2322
import com.google.common.base.MoreObjects;
2423
import com.google.common.base.Predicate;
2524
import io.grpc.Context;
@@ -28,6 +27,7 @@
2827
import java.util.concurrent.CancellationException;
2928
import java.util.concurrent.TimeoutException;
3029
import javax.annotation.Nullable;
30+
import javax.net.ssl.SSLHandshakeException;
3131

3232
/**
3333
* A factory for creating instances of {@link SpannerException} and its subtypes. All creation of
@@ -168,7 +168,9 @@ private static boolean isRetryable(ErrorCode code, @Nullable Throwable cause) {
168168
case INTERNAL:
169169
return hasCauseMatching(cause, Matchers.isRetryableInternalError);
170170
case UNAVAILABLE:
171-
return true;
171+
// SSLHandshakeException is (probably) not retryable, as it is an indication that the server
172+
// certificate was not accepted by the client.
173+
return !hasCauseMatching(cause, Matchers.isSSLHandshakeException);
172174
case RESOURCE_EXHAUSTED:
173175
return SpannerException.extractRetryDelay(cause) > 0;
174176
default:
@@ -211,5 +213,12 @@ public boolean apply(Throwable cause) {
211213
return false;
212214
}
213215
};
216+
static final Predicate<Throwable> isSSLHandshakeException =
217+
new Predicate<Throwable>() {
218+
@Override
219+
public boolean apply(Throwable input) {
220+
return input instanceof SSLHandshakeException;
221+
}
222+
};
214223
}
215224
}

branches/autosynth-containeranalysis/google-cloud-clients/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerImplTest.java

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,16 @@
1717
package com.google.cloud.spanner;
1818

1919
import static com.google.common.truth.Truth.assertThat;
20+
import static org.hamcrest.CoreMatchers.is;
21+
import static org.junit.Assert.assertThat;
2022
import static org.junit.Assert.fail;
2123

2224
import com.google.cloud.grpc.GrpcTransportOptions;
2325
import com.google.cloud.spanner.spi.v1.SpannerRpc;
2426
import java.util.HashMap;
2527
import java.util.Map;
2628
import java.util.concurrent.Callable;
29+
import javax.net.ssl.SSLHandshakeException;
2730
import org.junit.Before;
2831
import org.junit.Test;
2932
import org.junit.runner.RunWith;
@@ -133,4 +136,49 @@ public Void call() throws Exception {
133136
assertThat(e.getMessage().contains("Unexpected exception thrown"));
134137
}
135138
}
139+
140+
@Test
141+
public void sslHandshakeExceptionIsNotRetryable() {
142+
// Verify that a SpannerException with code UNAVAILABLE and cause SSLHandshakeException is not
143+
// retryable.
144+
boolean gotExpectedException = false;
145+
try {
146+
SpannerImpl.runWithRetries(
147+
new Callable<Object>() {
148+
@Override
149+
public Void call() throws Exception {
150+
throw SpannerExceptionFactory.newSpannerException(
151+
ErrorCode.UNAVAILABLE,
152+
"This exception should not be retryable",
153+
new SSLHandshakeException("some SSL handshake exception"));
154+
}
155+
});
156+
} catch (SpannerException e) {
157+
gotExpectedException = true;
158+
assertThat(e.isRetryable(), is(false));
159+
assertThat(e.getErrorCode()).isEqualTo(ErrorCode.UNAVAILABLE);
160+
assertThat(e.getMessage().contains("This exception should not be retryable"));
161+
}
162+
assertThat(gotExpectedException, is(true));
163+
164+
// Verify that any other SpannerException with code UNAVAILABLE is retryable.
165+
SpannerImpl.runWithRetries(
166+
new Callable<Object>() {
167+
private boolean firstTime = true;
168+
169+
@Override
170+
public Void call() throws Exception {
171+
// Keep track of whethr this is the first call or a subsequent call to avoid an infinite
172+
// loop.
173+
if (firstTime) {
174+
firstTime = false;
175+
throw SpannerExceptionFactory.newSpannerException(
176+
ErrorCode.UNAVAILABLE,
177+
"This exception should be retryable",
178+
new Exception("some other exception"));
179+
}
180+
return null;
181+
}
182+
});
183+
}
136184
}

0 commit comments

Comments
 (0)