Skip to content

Commit f03ce56

Browse files
docs: improve timeout and retry sample (#2630)
* docs: improve timeout and retry sample The timeout and retry sample used 60 seconds for both initial, max, and total timeout. It also used a 1.0 multiplier for the timeout value. This made it impossible to explain how to set an increasing RPC timeout value. It also rendered adding the DEADLINE_EXCEEDED error code as a retryable code superfluous. * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * chore: update timeout values based on what is possible with other languages * test: move sample test to separate class --------- Co-authored-by: Owl Bot <gcf-owl-bot[bot]@users.noreply.github.com>
1 parent 3f48624 commit f03ce56

File tree

4 files changed

+148
-3
lines changed

4 files changed

+148
-3
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright 2023 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.cloud.spanner;
18+
19+
import com.google.api.gax.grpc.testing.LocalChannelProvider;
20+
import com.google.cloud.NoCredentials;
21+
import io.grpc.Server;
22+
import io.grpc.inprocess.InProcessServerBuilder;
23+
import java.io.IOException;
24+
import org.junit.After;
25+
import org.junit.AfterClass;
26+
import org.junit.Before;
27+
import org.junit.BeforeClass;
28+
29+
abstract class AbstractMockServerTest {
30+
protected static MockSpannerServiceImpl mockSpanner;
31+
protected static Server server;
32+
protected static LocalChannelProvider channelProvider;
33+
34+
private Spanner spanner;
35+
36+
@BeforeClass
37+
public static void startMockServer() throws IOException {
38+
mockSpanner = new MockSpannerServiceImpl();
39+
mockSpanner.setAbortProbability(0.0D); // We don't want any unpredictable aborted transactions.
40+
41+
String uniqueName = InProcessServerBuilder.generateName();
42+
server = InProcessServerBuilder.forName(uniqueName).addService(mockSpanner).build().start();
43+
channelProvider = LocalChannelProvider.create(uniqueName);
44+
}
45+
46+
@AfterClass
47+
public static void stopMockServer() throws InterruptedException {
48+
server.shutdown();
49+
server.awaitTermination();
50+
}
51+
52+
@Before
53+
public void createSpannerInstance() {
54+
spanner =
55+
SpannerOptions.newBuilder()
56+
.setProjectId("test-project")
57+
.setChannelProvider(channelProvider)
58+
.setCredentials(NoCredentials.getInstance())
59+
.setSessionPoolOption(SessionPoolOptions.newBuilder().setFailOnSessionLeak().build())
60+
.build()
61+
.getService();
62+
}
63+
64+
@After
65+
public void cleanup() {
66+
spanner.close();
67+
mockSpanner.reset();
68+
mockSpanner.removeAllExecutionTimes();
69+
}
70+
}

google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseClientImplTest.java

-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@
4848
import com.google.cloud.spanner.AbstractResultSet.GrpcStreamIterator;
4949
import com.google.cloud.spanner.AsyncResultSet.CallbackResponse;
5050
import com.google.cloud.spanner.AsyncTransactionManager.TransactionContextFuture;
51-
import com.google.cloud.spanner.BaseSessionPoolTest.FakeClock;
5251
import com.google.cloud.spanner.MockSpannerServiceImpl.SimulatedExecutionTime;
5352
import com.google.cloud.spanner.MockSpannerServiceImpl.StatementResult;
5453
import com.google.cloud.spanner.Options.RpcPriority;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
* Copyright 2023 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.cloud.spanner;
18+
19+
import static org.junit.Assert.assertEquals;
20+
import static org.junit.Assert.assertThrows;
21+
22+
import com.google.api.gax.retrying.RetrySettings;
23+
import com.google.api.gax.rpc.StatusCode;
24+
import com.google.cloud.NoCredentials;
25+
import com.google.cloud.spanner.MockSpannerServiceImpl.StatementResult;
26+
import org.junit.Test;
27+
import org.junit.runner.RunWith;
28+
import org.junit.runners.JUnit4;
29+
import org.threeten.bp.Duration;
30+
31+
/** Tests for samples that use an in-mem mock server instead of running on real Cloud Spanner. */
32+
@RunWith(JUnit4.class)
33+
public class SamplesMockServerTest extends AbstractMockServerTest {
34+
35+
@Test
36+
public void testSampleRetrySettings() {
37+
String sql =
38+
"INSERT INTO Singers (SingerId, FirstName, LastName)\n"
39+
+ "VALUES (20, 'George', 'Washington')";
40+
mockSpanner.putStatementResult(StatementResult.update(Statement.of(sql), 1L));
41+
42+
SpannerOptions.Builder builder =
43+
SpannerOptions.newBuilder()
44+
.setProjectId("p")
45+
.setCredentials(NoCredentials.getInstance())
46+
.setChannelProvider(channelProvider);
47+
// Set a timeout value for the ExecuteSql RPC that is so low that it will always be triggered.
48+
// This should cause the RPC to fail with a DEADLINE_EXCEEDED error.
49+
builder
50+
.getSpannerStubSettingsBuilder()
51+
.executeSqlSettings()
52+
.setRetryableCodes(StatusCode.Code.UNAVAILABLE)
53+
.setRetrySettings(
54+
RetrySettings.newBuilder()
55+
.setInitialRetryDelay(Duration.ofMillis(500))
56+
.setMaxRetryDelay(Duration.ofSeconds(16))
57+
.setRetryDelayMultiplier(1.5)
58+
.setInitialRpcTimeout(Duration.ofNanos(1L))
59+
.setMaxRpcTimeout(Duration.ofNanos(1L))
60+
.setRpcTimeoutMultiplier(1.0)
61+
.setTotalTimeout(Duration.ofNanos(1L))
62+
.build());
63+
// Create a Spanner client using the custom retry and timeout settings.
64+
try (Spanner spanner = builder.build().getService()) {
65+
DatabaseClient client = spanner.getDatabaseClient(DatabaseId.of("p", "i", "d"));
66+
SpannerException exception =
67+
assertThrows(
68+
SpannerException.class,
69+
() ->
70+
client
71+
.readWriteTransaction()
72+
.run(transaction -> transaction.executeUpdate(Statement.of(sql))));
73+
assertEquals(ErrorCode.DEADLINE_EXCEEDED, exception.getErrorCode());
74+
}
75+
}
76+
}

samples/snippets/src/main/java/com/example/spanner/CustomTimeoutAndRetrySettingsExample.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,15 @@ static void executeSqlWithCustomTimeoutAndRetrySettings(
4949
.getSpannerStubSettingsBuilder()
5050
.executeSqlSettings()
5151
// Configure which errors should be retried.
52-
.setRetryableCodes(Code.DEADLINE_EXCEEDED, Code.UNAVAILABLE)
52+
.setRetryableCodes(Code.UNAVAILABLE)
5353
.setRetrySettings(
5454
RetrySettings.newBuilder()
5555
// Configure retry delay settings.
5656
// The initial amount of time to wait before retrying the request.
5757
.setInitialRetryDelay(Duration.ofMillis(500))
5858
// The maximum amount of time to wait before retrying. I.e. after this value is
5959
// reached, the wait time will not increase further by the multiplier.
60-
.setMaxRetryDelay(Duration.ofSeconds(64))
60+
.setMaxRetryDelay(Duration.ofSeconds(16))
6161
// The previous wait time is multiplied by this multiplier to come up with the next
6262
// wait time, until the max is reached.
6363
.setRetryDelayMultiplier(1.5)

0 commit comments

Comments
 (0)