Skip to content

Commit d60ed54

Browse files
committed
feat(batch): reconnect to GCP every 160 seconds
1 parent 825bd65 commit d60ed54

8 files changed

Lines changed: 83 additions & 20 deletions

File tree

src/main/java/io/weaviate/client6/v1/api/Config.java

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import io.weaviate.client6.v1.internal.ObjectBuilder;
1212
import io.weaviate.client6.v1.internal.Timeout;
1313
import io.weaviate.client6.v1.internal.TokenProvider;
14+
import io.weaviate.client6.v1.internal.TransportOptions;
1415
import io.weaviate.client6.v1.internal.grpc.GrpcChannelOptions;
1516
import io.weaviate.client6.v1.internal.rest.RestTransportOptions;
1617

@@ -181,17 +182,6 @@ public SelfT timeout(int initSeconds, int querySeconds, int insertSeconds) {
181182
private static final String HEADER_X_WEAVIATE_CLUSTER_URL = "X-Weaviate-Cluster-URL";
182183
private static final String HEADER_X_WEAVIATE_CLIENT = "X-Weaviate-Client";
183184

184-
/**
185-
* isWeaviateDomain returns true if the host matches weaviate.io,
186-
* semi.technology, or weaviate.cloud domain.
187-
*/
188-
private static boolean isWeaviateDomain(String host) {
189-
var lower = host.toLowerCase();
190-
return lower.contains("weaviate.io") ||
191-
lower.contains("semi.technology") ||
192-
lower.contains("weaviate.cloud");
193-
}
194-
195185
private static final String VERSION = "weaviate-client-java/"
196186
+ ((!BuildInfo.TAGS.isBlank() && BuildInfo.TAGS != "unknown") ? BuildInfo.TAGS
197187
: (BuildInfo.BRANCH + "-" + BuildInfo.COMMIT_ID_ABBREV));
@@ -200,7 +190,7 @@ private static boolean isWeaviateDomain(String host) {
200190
public Config build() {
201191
// For clusters hosted on Weaviate Cloud, Weaviate Embedding Service
202192
// will be available under the same domain.
203-
if (isWeaviateDomain(httpHost) && authentication != null) {
193+
if (TransportOptions.isWeaviateDomain(httpHost) && authentication != null) {
204194
setHeader(HEADER_X_WEAVIATE_CLUSTER_URL, "https://" + httpHost + ":" + httpPort);
205195
}
206196
setHeader(HEADER_X_WEAVIATE_CLIENT, VERSION);

src/main/java/io/weaviate/client6/v1/api/collections/batch/BatchContext.java

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ void setClosing(Exception ex) {
174174
this.queue = new ArrayBlockingQueue<>(DEFAULT_QUEUE_SIZE);
175175
this.batch = new Batch(DEFAULT_BATCH_SIZE, maxSizeBytes);
176176
setState(CLOSED);
177+
177178
}
178179

179180
/** Add {@link WeaviateObject} to the batch. */
@@ -701,9 +702,6 @@ public void onEnter(State prev) {
701702
* Reconnecting state is entererd either by the server finishing a shutdown
702703
* and closing it's end of the stream or an unexpected stream hangup.
703704
*
704-
* <p>
705-
*
706-
*
707705
* @see Recv#onCompleted graceful server shutdown
708706
* @see Recv#onError stream hangup
709707
*/
@@ -781,7 +779,6 @@ private void reconnectAfter(long delaySeconds) {
781779
} catch (ExecutionException e) {
782780
onEvent(new Event.ClientError(e));
783781
}
784-
785782
}, delaySeconds, TimeUnit.SECONDS);
786783
}
787784
}
@@ -844,4 +841,32 @@ public void onEnter(State prev) {
844841
closed = true;
845842
}
846843
};
844+
845+
// --------------------------------------------------------------------------
846+
847+
private final ScheduledExecutorService reconnectExec = Executors.newScheduledThreadPool(1);
848+
849+
void scheduleReconnect(int reconnectIntervalSeconds) {
850+
reconnectExec.scheduleWithFixedDelay(() -> {
851+
if (Thread.currentThread().isInterrupted()) {
852+
onEvent(Event.SHUTTING_DOWN);
853+
}
854+
if (Thread.currentThread().isInterrupted()) {
855+
onEvent(Event.EOF);
856+
}
857+
858+
// We want to count down from the moment we re-opened the stream,
859+
// not from the moment we initialited the sequence.
860+
lock.lock();
861+
try {
862+
while (state != ACTIVE) {
863+
stateChanged.await();
864+
}
865+
} catch (InterruptedException ignored) {
866+
// Let the process exit normally.
867+
} finally {
868+
lock.unlock();
869+
}
870+
}, reconnectIntervalSeconds, reconnectIntervalSeconds, TimeUnit.SECONDS);
871+
}
847872
}

src/main/java/io/weaviate/client6/v1/api/collections/batch/Event.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import java.util.Collection;
66
import java.util.List;
77
import java.util.Map;
8+
import java.util.OptionalInt;
89

910
import io.grpc.Status;
1011
import io.weaviate.client6.v1.api.collections.batch.Event.Acks;
@@ -20,12 +21,16 @@ sealed interface Event
2021
permits Started, Acks, Results, Backoff, Oom, TerminationEvent, StreamHangup, ClientError {
2122

2223
final static Event STARTED = new Started();
23-
final static Event OOM = TerminationEvent.OOM;
2424
final static Event SHUTTING_DOWN = TerminationEvent.SHUTTING_DOWN;
2525
final static Event EOF = TerminationEvent.EOF;
2626

27-
/** */
28-
record Started() implements Event {
27+
/**
28+
* The server has acknowledged our Start message and is ready to receive data.
29+
*
30+
* @param reconnectAfterSeconds Delay in seconds after which
31+
* the stream should be renewed.
32+
*/
33+
record Started(OptionalInt reconnectAfterSeconds) implements Event {
2934
}
3035

3136
/**

src/main/java/io/weaviate/client6/v1/api/collections/batch/WeaviateBatchClient.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import java.util.OptionalInt;
66

77
import io.weaviate.client6.v1.api.collections.CollectionHandleDefaults;
8+
import io.weaviate.client6.v1.internal.TransportOptions;
89
import io.weaviate.client6.v1.internal.grpc.GrpcTransport;
910
import io.weaviate.client6.v1.internal.orm.CollectionDescriptor;
1011

@@ -34,11 +35,24 @@ public BatchContext<PropertiesT> start() {
3435
if (maxSizeBytes.isEmpty()) {
3536
throw new IllegalStateException("Server must have grpcMaxMessageSize configured to use server-side batching");
3637
}
38+
3739
StreamFactory<Message, Event> streamFactory = new TranslatingStreamFactory(grpcTransport::createStream);
38-
return new BatchContext<>(
40+
BatchContext<PropertiesT> context = new BatchContext<>(
3941
streamFactory,
4042
maxSizeBytes.getAsInt(),
4143
collectionDescriptor,
4244
defaults);
45+
46+
if (isWeaviateCloudOnGoogleCloud(grpcTransport.host())) {
47+
context.scheduleReconnect(GCP_RECONNECT_INTERVAL_SECONDS);
48+
}
49+
50+
return context;
51+
}
52+
53+
private static final int GCP_RECONNECT_INTERVAL_SECONDS = 160;
54+
55+
private static boolean isWeaviateCloudOnGoogleCloud(String host) {
56+
return TransportOptions.isWeaviateDomain(host) && TransportOptions.isGoogleCloudDomain(host);
4357
}
4458
}

src/main/java/io/weaviate/client6/v1/internal/TransportOptions.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,20 @@ public H headers() {
5757
public TrustManagerFactory trustManagerFactory() {
5858
return this.trustManagerFactory;
5959
}
60+
61+
/**
62+
* isWeaviateDomain returns true if the host matches weaviate.io,
63+
* semi.technology, or weaviate.cloud domain.
64+
*/
65+
public static boolean isWeaviateDomain(String host) {
66+
var lower = host.toLowerCase();
67+
return lower.contains("weaviate.io") ||
68+
lower.contains("semi.technology") ||
69+
lower.contains("weaviate.cloud");
70+
}
71+
72+
public static boolean isGoogleCloudDomain(String host) {
73+
var lower = host.toLowerCase();
74+
return lower.contains("gcp");
75+
}
6076
}

src/main/java/io/weaviate/client6/v1/internal/grpc/DefaultGrpcTransport.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,4 +177,9 @@ public void close() throws Exception {
177177
callCredentials.close();
178178
}
179179
}
180+
181+
@Override
182+
public String host() {
183+
return transportOptions.host();
184+
}
180185
}

src/main/java/io/weaviate/client6/v1/internal/grpc/GrpcTransport.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ <RequestT, RequestM, ReplyM, ResponseT> CompletableFuture<ResponseT> performRequ
2323
StreamObserver<WeaviateProtoBatch.BatchStreamRequest> createStream(
2424
StreamObserver<WeaviateProtoBatch.BatchStreamReply> recv);
2525

26+
String host();
27+
2628
/**
2729
* Maximum inbound/outbound message size supported by the underlying channel.
2830
*/

src/test/java/io/weaviate/testutil/transport/MockGrpcTransport.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import io.weaviate.client6.v1.internal.grpc.protocol.WeaviateProtoBatch.BatchStreamRequest;
1818

1919
public class MockGrpcTransport implements GrpcTransport {
20+
private final String host = "example.com";
2021

2122
@FunctionalInterface
2223
public interface AssertFunction {
@@ -73,4 +74,9 @@ public OptionalInt maxMessageSizeBytes() {
7374
// TODO(dyma): implement for tests
7475
throw new UnsupportedOperationException("Unimplemented method 'maxMessageSizeBytes'");
7576
}
77+
78+
@Override
79+
public String host() {
80+
return host;
81+
}
7682
}

0 commit comments

Comments
 (0)