Skip to content
This repository was archived by the owner on Feb 24, 2026. It is now read-only.

Commit 65c5ec9

Browse files
authored
fix: more writeapi manual client test issues (#241)
* fix: more test issues - Fix some unwanted exceptions in the test run by make sure writers are cleaned up. - Fix another executor race issue. - The reconnection test failure is wired, it seems the test was shut down while running. I split the tests into 3 and reduce its run length. It could be due to testing taking too long to run (each wait is 7 seconds and there were 4 waits). modified: google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1alpha2/StreamWriter.java modified: google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1alpha2/WriterCache.java modified: google-cloud-bigquerystorage/src/test/java/com/google/cloud/bigquery/storage/v1alpha2/StreamWriterTest.java modified: google-cloud-bigquerystorage/src/test/java/com/google/cloud/bigquery/storage/v1alpha2/WriterCacheTest.java * remove some unhonored retry setting checks
1 parent 89c8623 commit 65c5ec9

4 files changed

Lines changed: 68 additions & 13 deletions

File tree

google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1alpha2/StreamWriter.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -165,10 +165,14 @@ private StreamWriter(Builder builder)
165165
Instant.ofEpochSecond(
166166
stream.getCreateTime().getSeconds(), stream.getCreateTime().getNanos());
167167
if (stream.getType() == Stream.WriteStream.Type.PENDING && stream.hasCommitTime()) {
168+
backgroundResources.shutdown();
169+
backgroundResources.awaitTermination(1, TimeUnit.MINUTES);
168170
throw new IllegalStateException(
169171
"Cannot write to a stream that is already committed: " + streamName);
170172
}
171173
if (createTime.plus(streamTTL).compareTo(Instant.now()) < 0) {
174+
backgroundResources.shutdown();
175+
backgroundResources.awaitTermination(1, TimeUnit.MINUTES);
172176
throw new IllegalStateException(
173177
"Cannot write to a stream that is already expired: " + streamName);
174178
}
@@ -247,7 +251,7 @@ public ApiFuture<AppendRowsResponse> append(AppendRowsRequest message) {
247251
*/
248252
public void refreshAppend() throws IOException, InterruptedException {
249253
synchronized (this) {
250-
Preconditions.checkState(!shutdown.get(), "Cannot append on a shut-down writer.");
254+
Preconditions.checkState(!shutdown.get(), "Cannot shut down on a shut-down writer.");
251255
// There could be a moment, stub is not yet initialized.
252256
if (clientStream != null) {
253257
clientStream.closeSend();
@@ -475,6 +479,7 @@ public RetrySettings getRetrySettings() {
475479
public void shutdown() {
476480
Preconditions.checkState(
477481
!shutdown.getAndSet(true), "Cannot shut down a writer already shut-down.");
482+
LOG.info("Shutdown called on writer");
478483
if (currentAlarmFuture != null && activeAlarm.getAndSet(false)) {
479484
currentAlarmFuture.cancel(false);
480485
}
@@ -684,10 +689,6 @@ > getApiMaxInflightRequests()) {
684689
*/
685690
public Builder setRetrySettings(RetrySettings retrySettings) {
686691
Preconditions.checkNotNull(retrySettings);
687-
Preconditions.checkArgument(
688-
retrySettings.getTotalTimeout().compareTo(MIN_TOTAL_TIMEOUT) >= 0);
689-
Preconditions.checkArgument(
690-
retrySettings.getInitialRpcTimeout().compareTo(MIN_RPC_TIMEOUT) >= 0);
691692
this.retrySettings = retrySettings;
692693
return this;
693694
}

google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1alpha2/WriterCache.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
import com.google.common.annotations.VisibleForTesting;
1919
import com.google.common.cache.Cache;
2020
import com.google.common.cache.CacheBuilder;
21+
import com.google.common.cache.RemovalListener;
22+
import com.google.common.cache.RemovalNotification;
2123
import com.google.protobuf.Descriptors.Descriptor;
2224
import java.io.IOException;
2325
import java.util.concurrent.ConcurrentMap;
@@ -53,6 +55,15 @@ private WriterCache(BigQueryWriteClient stub, int maxTableEntry, SchemaCompact c
5355
writerCache =
5456
CacheBuilder.newBuilder()
5557
.maximumSize(maxTableEntry)
58+
.removalListener(
59+
new RemovalListener<String, Cache<Descriptor, StreamWriter>>() {
60+
@Override
61+
public void onRemoval(
62+
RemovalNotification<String, Cache<Descriptor, StreamWriter>>
63+
removalNotification) {
64+
removalNotification.getValue().invalidateAll();
65+
}
66+
})
5667
.<String, Cache<Descriptor, StreamWriter>>build();
5768
}
5869

@@ -135,6 +146,14 @@ public StreamWriter getTableWriter(String tableName, Descriptor userSchema)
135146
tableEntry =
136147
CacheBuilder.newBuilder()
137148
.maximumSize(MAX_WRITERS_PER_TABLE)
149+
.removalListener(
150+
new RemovalListener<Descriptor, StreamWriter>() {
151+
@Override
152+
public void onRemoval(
153+
RemovalNotification<Descriptor, StreamWriter> removalNotification) {
154+
removalNotification.getValue().close();
155+
}
156+
})
138157
.<Descriptor, StreamWriter>build();
139158
writer = CreateNewWriter(streamName);
140159
tableEntry.put(userSchema, writer);

google-cloud-bigquerystorage/src/test/java/com/google/cloud/bigquery/storage/v1alpha2/StreamWriterTest.java

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import com.google.api.gax.grpc.testing.LocalChannelProvider;
3434
import com.google.api.gax.grpc.testing.MockGrpcService;
3535
import com.google.api.gax.grpc.testing.MockServiceHelper;
36+
import com.google.api.gax.retrying.RetrySettings;
3637
import com.google.api.gax.rpc.DataLossException;
3738
import com.google.cloud.bigquery.storage.test.Test.FooType;
3839
import com.google.cloud.bigquery.storage.v1alpha2.Storage.*;
@@ -439,7 +440,7 @@ public void testFlowControlBehaviorException() throws Exception {
439440
}
440441

441442
@Test
442-
public void testStreamReconnection() throws Exception {
443+
public void testStreamReconnectionTransient() throws Exception {
443444
StreamWriter writer =
444445
getTestStreamWriterBuilder()
445446
.setBatchingSettings(
@@ -450,17 +451,27 @@ public void testStreamReconnection() throws Exception {
450451
.build())
451452
.build();
452453

453-
// Case 1: Request succeeded after retry since the error is transient.
454454
StatusRuntimeException transientError = new StatusRuntimeException(Status.UNAVAILABLE);
455455
testBigQueryWrite.addException(transientError);
456456
testBigQueryWrite.addResponse(AppendRowsResponse.newBuilder().setOffset(0).build());
457457
ApiFuture<AppendRowsResponse> future1 = sendTestMessage(writer, new String[] {"m1"});
458458
assertEquals(false, future1.isDone());
459459
// Retry is scheduled to be 7 seconds later.
460460
assertEquals(0L, future1.get().getOffset());
461+
writer.close();
462+
}
461463

462-
LOG.info("======CASE II");
463-
// Case 2 : Request failed since the error is not transient.
464+
@Test
465+
public void testStreamReconnectionPermanant() throws Exception {
466+
StreamWriter writer =
467+
getTestStreamWriterBuilder()
468+
.setBatchingSettings(
469+
StreamWriter.Builder.DEFAULT_BATCHING_SETTINGS
470+
.toBuilder()
471+
.setDelayThreshold(Duration.ofSeconds(100000))
472+
.setElementCountThreshold(1L)
473+
.build())
474+
.build();
464475
StatusRuntimeException permanentError = new StatusRuntimeException(Status.INVALID_ARGUMENT);
465476
testBigQueryWrite.addException(permanentError);
466477
ApiFuture<AppendRowsResponse> future2 = sendTestMessage(writer, new String[] {"m2"});
@@ -470,11 +481,26 @@ public void testStreamReconnection() throws Exception {
470481
} catch (ExecutionException e) {
471482
assertEquals(permanentError.toString(), e.getCause().getCause().toString());
472483
}
484+
writer.close();
485+
}
473486

474-
LOG.info("======CASE III");
475-
// Case 3: Failed after retried max retry times.
476-
testBigQueryWrite.addException(transientError);
477-
testBigQueryWrite.addException(transientError);
487+
@Test
488+
public void testStreamReconnectionExceedRetry() throws Exception {
489+
StreamWriter writer =
490+
getTestStreamWriterBuilder()
491+
.setBatchingSettings(
492+
StreamWriter.Builder.DEFAULT_BATCHING_SETTINGS
493+
.toBuilder()
494+
.setDelayThreshold(Duration.ofSeconds(100000))
495+
.setElementCountThreshold(1L)
496+
.build())
497+
.setRetrySettings(
498+
RetrySettings.newBuilder()
499+
.setMaxRetryDelay(Duration.ofMillis(100))
500+
.setMaxAttempts(1)
501+
.build())
502+
.build();
503+
StatusRuntimeException transientError = new StatusRuntimeException(Status.UNAVAILABLE);
478504
testBigQueryWrite.addException(transientError);
479505
testBigQueryWrite.addException(transientError);
480506
ApiFuture<AppendRowsResponse> future3 = sendTestMessage(writer, new String[] {"m3"});
@@ -814,5 +840,7 @@ public void testExistingClient() throws Exception {
814840
StreamWriter writer = StreamWriter.newBuilder(TEST_STREAM, client).build();
815841
writer.close();
816842
assertFalse(client.isShutdown());
843+
client.shutdown();
844+
client.awaitTermination(1, TimeUnit.MINUTES);
817845
}
818846
}

google-cloud-bigquerystorage/src/test/java/com/google/cloud/bigquery/storage/v1alpha2/WriterCacheTest.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import java.util.UUID;
3434
import java.util.concurrent.ExecutorService;
3535
import java.util.concurrent.Executors;
36+
import java.util.concurrent.TimeUnit;
3637
import java.util.logging.Logger;
3738
import org.junit.*;
3839
import org.junit.runner.RunWith;
@@ -285,5 +286,11 @@ public void run() {
285286
}
286287
});
287288
}
289+
executor.shutdown();
290+
try {
291+
executor.awaitTermination(1, TimeUnit.MINUTES);
292+
} catch (InterruptedException e) {
293+
LOG.info(e.toString());
294+
}
288295
}
289296
}

0 commit comments

Comments
 (0)