Skip to content

Commit ae6f8bd

Browse files
authored
chore: Enable exponential backoff for retries in tests (#4059)
* chore: Enable exponential backoff for retries in tests * chore: Clone table for DML query tests * chore: Use GCA retry settings code suggestion
1 parent ea0cd57 commit ae6f8bd

File tree

3 files changed

+106
-52
lines changed

3 files changed

+106
-52
lines changed

google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/testing/RemoteBigQueryHelper.java

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public class RemoteBigQueryHelper {
4545
private static final String MODEL_NAME_PREFIX = "model_";
4646
private static final String ROUTINE_NAME_PREFIX = "routine_";
4747
private final BigQueryOptions options;
48-
private static final int connectTimeout = 60000;
48+
private static final int CONNECT_TIMEOUT_IN_MS = 60000;
4949

5050
private RemoteBigQueryHelper(BigQueryOptions options) {
5151
this.options = options;
@@ -96,8 +96,8 @@ public static RemoteBigQueryHelper create(String projectId, InputStream keyStrea
9696
HttpTransportOptions transportOptions = BigQueryOptions.getDefaultHttpTransportOptions();
9797
transportOptions =
9898
transportOptions.toBuilder()
99-
.setConnectTimeout(connectTimeout)
100-
.setReadTimeout(connectTimeout)
99+
.setConnectTimeout(CONNECT_TIMEOUT_IN_MS)
100+
.setReadTimeout(CONNECT_TIMEOUT_IN_MS)
101101
.build();
102102
BigQueryOptions bigqueryOptions =
103103
BigQueryOptions.newBuilder()
@@ -133,8 +133,8 @@ public static RemoteBigQueryHelper create(BigQueryOptions.Builder bigqueryOption
133133
HttpTransportOptions transportOptions = BigQueryOptions.getDefaultHttpTransportOptions();
134134
transportOptions =
135135
transportOptions.toBuilder()
136-
.setConnectTimeout(connectTimeout)
137-
.setReadTimeout(connectTimeout)
136+
.setConnectTimeout(CONNECT_TIMEOUT_IN_MS)
137+
.setReadTimeout(CONNECT_TIMEOUT_IN_MS)
138138
.build();
139139
BigQueryOptions.Builder builder =
140140
bigqueryOptionsBuilder
@@ -143,21 +143,25 @@ public static RemoteBigQueryHelper create(BigQueryOptions.Builder bigqueryOption
143143
return new RemoteBigQueryHelper(builder.build());
144144
}
145145

146+
// Opt to keep these settings a small as possible to minimize the total test time.
147+
// These values can be adjusted per test case, but these serve as default values.
146148
private static RetrySettings retrySettings() {
147-
double retryDelayMultiplier = 1.0;
149+
double backoffMultiplier = 1.5;
148150
int maxAttempts = 10;
149-
long initialRetryDelay = 250L;
150-
long maxRetryDelay = 30000L;
151-
long totalTimeOut = 120000L;
151+
long initialRetryDelayMs = 100L; // 0.1s initial retry delay
152+
long maxRetryDelayMs = 1000L; // 1s max retry delay between retry
153+
long initialRpcTimeoutMs = 1000L; // 1s initial rpc duration
154+
long maxRpcTimeoutMs = 2000L; // 2s max rpc duration
155+
long totalTimeoutMs = 3000L; // 3s total timeout
152156
return RetrySettings.newBuilder()
153157
.setMaxAttempts(maxAttempts)
154-
.setMaxRetryDelayDuration(Duration.ofMillis(maxRetryDelay))
155-
.setTotalTimeoutDuration(Duration.ofMillis(totalTimeOut))
156-
.setInitialRetryDelayDuration(Duration.ofMillis(initialRetryDelay))
157-
.setRetryDelayMultiplier(retryDelayMultiplier)
158-
.setInitialRpcTimeoutDuration(Duration.ofMillis(totalTimeOut))
159-
.setRpcTimeoutMultiplier(retryDelayMultiplier)
160-
.setMaxRpcTimeoutDuration(Duration.ofMillis(totalTimeOut))
158+
.setTotalTimeoutDuration(Duration.ofMillis(totalTimeoutMs))
159+
.setInitialRetryDelayDuration(Duration.ofMillis(initialRetryDelayMs))
160+
.setMaxRetryDelayDuration(Duration.ofMillis(maxRetryDelayMs))
161+
.setRetryDelayMultiplier(backoffMultiplier)
162+
.setInitialRpcTimeoutDuration(Duration.ofMillis(initialRpcTimeoutMs))
163+
.setMaxRpcTimeoutDuration(Duration.ofMillis(maxRpcTimeoutMs))
164+
.setRpcTimeoutMultiplier(backoffMultiplier)
161165
.build();
162166
}
163167

google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java

Lines changed: 80 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,7 @@ class ITBigQueryTest {
477477
Field.newBuilder("BooleanField", LegacySQLTypeName.BOOLEAN)
478478
.setDescription("BooleanDescription")
479479
.build();
480-
private static final Schema DDL_TABLE_SCHEMA =
480+
private static final Schema SIMPLE_TABLE_SCHEMA =
481481
Schema.of(DDL_TIMESTAMP_FIELD_SCHEMA, DDL_STRING_FIELD_SCHEMA, DDL_BOOLEAN_FIELD_SCHEMA);
482482
private static final Schema LARGE_TABLE_SCHEMA =
483483
Schema.of(
@@ -622,7 +622,7 @@ class ITBigQueryTest {
622622
private static final String EXTRACT_MODEL_FILE = "extract_model.csv";
623623
private static final String BUCKET = RemoteStorageHelper.generateBucketName();
624624
private static final TableId TABLE_ID = TableId.of(DATASET, generateTableName("testing_table"));
625-
private static final TableId TABLE_ID_DDL =
625+
private static final TableId TABLE_ID_SIMPLE =
626626
TableId.of(DATASET, generateTableName("ddl_testing_table"));
627627
private static final TableId TABLE_ID_FAST_QUERY =
628628
TableId.of(DATASET, generateTableName("fast_query_testing_table"));
@@ -1163,9 +1163,11 @@ static void beforeClass() throws InterruptedException, IOException {
11631163

11641164
LoadJobConfiguration configurationDDL =
11651165
LoadJobConfiguration.newBuilder(
1166-
TABLE_ID_DDL, "gs://" + BUCKET + "/" + JSON_LOAD_FILE_SIMPLE, FormatOptions.json())
1166+
TABLE_ID_SIMPLE,
1167+
"gs://" + BUCKET + "/" + JSON_LOAD_FILE_SIMPLE,
1168+
FormatOptions.json())
11671169
.setCreateDisposition(JobInfo.CreateDisposition.CREATE_IF_NEEDED)
1168-
.setSchema(DDL_TABLE_SCHEMA)
1170+
.setSchema(SIMPLE_TABLE_SCHEMA)
11691171
.setLabels(labels)
11701172
.build();
11711173
Job jobDDL = bigquery.create(JobInfo.of(configurationDDL));
@@ -4773,24 +4775,41 @@ void testFastSQLQueryMultiPage() throws InterruptedException {
47734775

47744776
@Test
47754777
void testFastDMLQuery() throws InterruptedException {
4776-
String tableName = TABLE_ID_FAST_QUERY.getTable();
4778+
// The test runs an update query. Clone the table to ensure that this doesn't impact
4779+
// other tests.
4780+
String tableName = generateTableName("test_table_fast_query_dml");
4781+
String tableNameFastQuery = TABLE_ID_SIMPLE.getTable();
4782+
String ddlQuery =
4783+
String.format(
4784+
"CREATE OR REPLACE TABLE %s ("
4785+
+ "TimestampField TIMESTAMP OPTIONS(description='TimestampDescription'), "
4786+
+ "StringField STRING OPTIONS(description='StringDescription'), "
4787+
+ "BooleanField BOOLEAN OPTIONS(description='BooleanDescription') "
4788+
+ ") AS SELECT DISTINCT * FROM %s",
4789+
tableName, tableNameFastQuery);
4790+
QueryJobConfiguration ddlConfig =
4791+
QueryJobConfiguration.newBuilder(ddlQuery).setDefaultDataset(DatasetId.of(DATASET)).build();
4792+
TableResult result = bigquery.query(ddlConfig);
4793+
assertNotNull(result.getJobId());
4794+
47774795
String dmlQuery =
47784796
String.format("UPDATE %s.%s SET StringField = 'hello' WHERE TRUE", DATASET, tableName);
47794797
QueryJobConfiguration dmlConfig = QueryJobConfiguration.newBuilder(dmlQuery).build();
4780-
TableResult result = bigquery.query(dmlConfig);
4781-
assertNotNull(result.getJobId());
4782-
assertEquals(TABLE_SCHEMA, result.getSchema());
4798+
TableResult resultAfterDML = bigquery.query(dmlConfig);
4799+
assertNotNull(resultAfterDML.getJobId());
4800+
assertEquals(SIMPLE_TABLE_SCHEMA, resultAfterDML.getSchema());
47834801
// Using the job reference on the TableResult, lookup and verify DML statistics.
4784-
Job queryJob = bigquery.getJob(result.getJobId());
4802+
Job queryJob = bigquery.getJob(resultAfterDML.getJobId());
4803+
queryJob = queryJob.waitFor();
47854804
JobStatistics.QueryStatistics statistics = queryJob.getStatistics();
4786-
assertEquals(2L, statistics.getNumDmlAffectedRows().longValue());
4787-
assertEquals(2L, statistics.getDmlStats().getUpdatedRowCount().longValue());
4805+
assertEquals(1L, statistics.getNumDmlAffectedRows().longValue());
4806+
assertEquals(1L, statistics.getDmlStats().getUpdatedRowCount().longValue());
47884807
}
47894808

47904809
@Test
47914810
void testFastDDLQuery() throws InterruptedException {
4792-
String tableName = "test_table_fast_query_ddl";
4793-
String tableNameFastQuery = TABLE_ID_DDL.getTable();
4811+
String tableName = generateTableName("test_table_fast_query_ddl");
4812+
String tableNameFastQuery = TABLE_ID_SIMPLE.getTable();
47944813
String ddlQuery =
47954814
String.format(
47964815
"CREATE OR REPLACE TABLE %s ("
@@ -4803,7 +4822,7 @@ void testFastDDLQuery() throws InterruptedException {
48034822
QueryJobConfiguration.newBuilder(ddlQuery).setDefaultDataset(DatasetId.of(DATASET)).build();
48044823
TableResult result = bigquery.query(ddlConfig);
48054824
assertNotNull(result.getJobId());
4806-
assertEquals(DDL_TABLE_SCHEMA, result.getSchema());
4825+
assertEquals(SIMPLE_TABLE_SCHEMA, result.getSchema());
48074826
assertEquals(0, result.getTotalRows());
48084827
// Verify correctness of table content
48094828
String sqlQuery = String.format("SELECT * FROM %s.%s", DATASET, tableName);
@@ -5078,29 +5097,61 @@ void testExecuteSelectSessionSupport() throws BigQuerySQLException {
50785097

50795098
@Test
50805099
void testDmlStatistics() throws InterruptedException {
5081-
String tableName = TABLE_ID_FAST_QUERY.getTable();
5082-
// Run a DML statement to UPDATE 2 rows of data
5100+
// This runs an update SQL query. Clone the table to ensure that this doesn't impact
5101+
// other tests.
5102+
String tableName = generateTableName("test_table_dml_stats");
5103+
String tableNameSimple = TABLE_ID_SIMPLE.getTable();
5104+
String ddlQuery =
5105+
String.format(
5106+
"CREATE OR REPLACE TABLE %s ("
5107+
+ "TimestampField TIMESTAMP OPTIONS(description='TimestampDescription'), "
5108+
+ "StringField STRING OPTIONS(description='StringDescription'), "
5109+
+ "BooleanField BOOLEAN OPTIONS(description='BooleanDescription') "
5110+
+ ") AS SELECT DISTINCT * FROM %s",
5111+
tableName, tableNameSimple);
5112+
QueryJobConfiguration ddlConfig =
5113+
QueryJobConfiguration.newBuilder(ddlQuery).setDefaultDataset(DatasetId.of(DATASET)).build();
5114+
TableResult result = bigquery.query(ddlConfig);
5115+
assertNotNull(result.getJobId());
5116+
50835117
String dmlQuery =
50845118
String.format("UPDATE %s.%s SET StringField = 'hello' WHERE TRUE", DATASET, tableName);
50855119
QueryJobConfiguration dmlConfig = QueryJobConfiguration.newBuilder(dmlQuery).build();
50865120
Job remoteJob = bigquery.create(JobInfo.of(dmlConfig));
50875121
remoteJob = remoteJob.waitFor();
50885122
assertNull(remoteJob.getStatus().getError());
50895123

5090-
TableResult result = remoteJob.getQueryResults();
5091-
assertNotNull(result.getJobId());
5092-
assertEquals(TABLE_SCHEMA, result.getSchema());
5124+
TableResult resultAfterUpdate = remoteJob.getQueryResults();
5125+
assertNotNull(resultAfterUpdate.getJobId());
5126+
assertEquals(SIMPLE_TABLE_SCHEMA, resultAfterUpdate.getSchema());
50935127

50945128
Job queryJob = bigquery.getJob(remoteJob.getJobId());
5129+
queryJob = queryJob.waitFor();
50955130
JobStatistics.QueryStatistics statistics = queryJob.getStatistics();
5096-
assertEquals(2L, statistics.getNumDmlAffectedRows().longValue());
5097-
assertEquals(2L, statistics.getDmlStats().getUpdatedRowCount().longValue());
5131+
assertEquals(1L, statistics.getNumDmlAffectedRows().longValue());
5132+
assertEquals(1L, statistics.getDmlStats().getUpdatedRowCount().longValue());
50985133
}
50995134

51005135
/* TODO(prasmish): replicate the entire test case for executeSelect */
51015136
@Test
51025137
void testTransactionInfo() throws InterruptedException {
5103-
String tableName = TABLE_ID_FAST_QUERY.getTable();
5138+
// The transaction runs an update query. Clone the table to ensure that this doesn't impact
5139+
// other tests.
5140+
String tableName = generateTableName("test_table_transaction_info");
5141+
String tableNameSimple = TABLE_ID_SIMPLE.getTable();
5142+
String ddlQuery =
5143+
String.format(
5144+
"CREATE OR REPLACE TABLE %s ("
5145+
+ "TimestampField TIMESTAMP OPTIONS(description='TimestampDescription'), "
5146+
+ "StringField STRING OPTIONS(description='StringDescription'), "
5147+
+ "BooleanField BOOLEAN OPTIONS(description='BooleanDescription') "
5148+
+ ") AS SELECT DISTINCT * FROM %s",
5149+
tableName, tableNameSimple);
5150+
QueryJobConfiguration ddlConfig =
5151+
QueryJobConfiguration.newBuilder(ddlQuery).setDefaultDataset(DatasetId.of(DATASET)).build();
5152+
TableResult result = bigquery.query(ddlConfig);
5153+
assertNotNull(result.getJobId());
5154+
51045155
String transaction =
51055156
String.format(
51065157
"BEGIN TRANSACTION;\n"
@@ -5913,7 +5964,7 @@ void testCopyJobStatistics() throws InterruptedException, TimeoutException {
59135964
@Test
59145965
void testSnapshotTableCopyJob() throws InterruptedException {
59155966
String sourceTableName = "test_copy_job_base_table";
5916-
String ddlTableName = TABLE_ID_DDL.getTable();
5967+
String ddlTableName = TABLE_ID_SIMPLE.getTable();
59175968
// this creates a snapshot table at specified snapshotTime
59185969
String snapshotTableName = "test_snapshot_table";
59195970
// Create source table with some data in it
@@ -5930,7 +5981,7 @@ void testSnapshotTableCopyJob() throws InterruptedException {
59305981
TableId sourceTableId = TableId.of(DATASET, sourceTableName);
59315982
TableResult result = bigquery.query(ddlConfig);
59325983
assertNotNull(result.getJobId());
5933-
assertEquals(DDL_TABLE_SCHEMA, result.getSchema());
5984+
assertEquals(SIMPLE_TABLE_SCHEMA, result.getSchema());
59345985
Table remoteTable = bigquery.getTable(DATASET, sourceTableName);
59355986
assertNotNull(remoteTable);
59365987

@@ -5952,7 +6003,7 @@ void testSnapshotTableCopyJob() throws InterruptedException {
59526003
assertEquals(snapshotTableId.getDataset(), snapshotTable.getTableId().getDataset());
59536004
assertEquals(snapshotTableName, snapshotTable.getTableId().getTable());
59546005
assertTrue(snapshotTable.getDefinition() instanceof SnapshotTableDefinition);
5955-
assertEquals(DDL_TABLE_SCHEMA, snapshotTable.getDefinition().getSchema());
6006+
assertEquals(SIMPLE_TABLE_SCHEMA, snapshotTable.getDefinition().getSchema());
59566007
assertNotNull(((SnapshotTableDefinition) snapshotTable.getDefinition()).getSnapshotTime());
59576008
assertEquals(
59586009
sourceTableName,
@@ -5978,7 +6029,7 @@ void testSnapshotTableCopyJob() throws InterruptedException {
59786029
assertNotNull(restoredTable);
59796030
assertEquals(restoredTableId.getDataset(), restoredTable.getTableId().getDataset());
59806031
assertEquals(restoredTableName, restoredTable.getTableId().getTable());
5981-
assertEquals(DDL_TABLE_SCHEMA, restoredTable.getDefinition().getSchema());
6032+
assertEquals(SIMPLE_TABLE_SCHEMA, restoredTable.getDefinition().getSchema());
59826033
assertEquals(snapshotTable.getNumBytes(), restoredTable.getNumBytes());
59836034
assertEquals(snapshotTable.getNumRows(), restoredTable.getNumRows());
59846035

@@ -6857,7 +6908,7 @@ void testCreateExternalTableWithReferenceFileSchemaParquet() {
68576908
@Test
68586909
void testCloneTableCopyJob() throws InterruptedException {
68596910
String sourceTableName = "test_copy_job_base_table";
6860-
String ddlTableName = TABLE_ID_DDL.getTable();
6911+
String ddlTableName = TABLE_ID_SIMPLE.getTable();
68616912
String cloneTableName = "test_clone_table";
68626913
// Create source table with some data in it
68636914
String ddlQuery =
@@ -6873,7 +6924,7 @@ void testCloneTableCopyJob() throws InterruptedException {
68736924
TableId sourceTableId = TableId.of(DATASET, sourceTableName);
68746925
TableResult result = bigquery.query(ddlConfig);
68756926
assertNotNull(result.getJobId());
6876-
assertEquals(DDL_TABLE_SCHEMA, result.getSchema());
6927+
assertEquals(SIMPLE_TABLE_SCHEMA, result.getSchema());
68776928
Table remoteTable = bigquery.getTable(DATASET, sourceTableName);
68786929
assertNotNull(remoteTable);
68796930

@@ -6897,7 +6948,7 @@ void testCloneTableCopyJob() throws InterruptedException {
68976948
assertEquals(cloneTableName, cloneTable.getTableId().getTable());
68986949
assertEquals(TableDefinition.Type.TABLE, cloneTable.getDefinition().getType());
68996950
assertTrue(cloneTable.getDefinition() instanceof StandardTableDefinition);
6900-
assertEquals(DDL_TABLE_SCHEMA, cloneTable.getDefinition().getSchema());
6951+
assertEquals(SIMPLE_TABLE_SCHEMA, cloneTable.getDefinition().getSchema());
69016952
assertTrue(cloneTable.getCloneDefinition() instanceof CloneDefinition);
69026953
assertEquals(sourceTableName, cloneTable.getCloneDefinition().getBaseTableId().getTable());
69036954
assertNotNull(cloneTable.getCloneDefinition().getCloneTime());

google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/testing/RemoteBigQueryHelperTest.java

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,13 @@
2626
import java.io.ByteArrayInputStream;
2727
import java.io.InputStream;
2828
import java.time.Duration;
29-
import java.util.concurrent.ExecutionException;
3029
import org.junit.jupiter.api.Test;
3130
import org.junit.jupiter.api.extension.ExtendWith;
3231
import org.mockito.Mockito;
3332
import org.mockito.junit.jupiter.MockitoExtension;
3433

3534
@ExtendWith(MockitoExtension.class)
36-
public class RemoteBigQueryHelperTest {
35+
class RemoteBigQueryHelperTest {
3736

3837
private static final String DATASET_NAME = "dataset-name";
3938
private static final String PROJECT_ID = "project-id";
@@ -67,7 +66,7 @@ public class RemoteBigQueryHelperTest {
6766
private static final InputStream JSON_KEY_STREAM = new ByteArrayInputStream(JSON_KEY.getBytes());
6867

6968
@Test
70-
public void testForceDelete() throws InterruptedException, ExecutionException {
69+
void testForceDelete() {
7170
BigQuery bigqueryMock = Mockito.mock(BigQuery.class);
7271
Mockito.when(bigqueryMock.delete(DATASET_NAME, DatasetDeleteOption.deleteContents()))
7372
.thenReturn(true);
@@ -76,15 +75,15 @@ public void testForceDelete() throws InterruptedException, ExecutionException {
7675
}
7776

7877
@Test
79-
public void testCreateFromStream() {
78+
void testCreateFromStream() {
8079
RemoteBigQueryHelper helper = RemoteBigQueryHelper.create(PROJECT_ID, JSON_KEY_STREAM);
8180
BigQueryOptions options = helper.getOptions();
8281
assertEquals(PROJECT_ID, options.getProjectId());
8382
assertEquals(60000, ((HttpTransportOptions) options.getTransportOptions()).getConnectTimeout());
8483
assertEquals(60000, ((HttpTransportOptions) options.getTransportOptions()).getReadTimeout());
8584
assertEquals(10, options.getRetrySettings().getMaxAttempts());
86-
assertEquals(Duration.ofMillis(30000), options.getRetrySettings().getMaxRetryDelayDuration());
87-
assertEquals(Duration.ofMillis(120000), options.getRetrySettings().getTotalTimeoutDuration());
88-
assertEquals(Duration.ofMillis(250), options.getRetrySettings().getInitialRetryDelayDuration());
85+
assertEquals(Duration.ofMillis(1000), options.getRetrySettings().getMaxRetryDelayDuration());
86+
assertEquals(Duration.ofMillis(3000), options.getRetrySettings().getTotalTimeoutDuration());
87+
assertEquals(Duration.ofMillis(100), options.getRetrySettings().getInitialRetryDelayDuration());
8988
}
9089
}

0 commit comments

Comments
 (0)