Skip to content

Commit 835ac71

Browse files
authored
couchbase: wait until query engine knows about bucket before creating… (#2662)
The motivation for this change is that in slow environments, it could be that the query engine is not aware of the just created bucket yet and so the create primary index will take longer than the 10s read timeout for the subsequent http request. As a result, this is just another precaution to minimize the chances that in slow environments the create primary index call times out with a read timeout.
1 parent 6e1f8a0 commit 835ac71

File tree

1 file changed

+30
-15
lines changed

1 file changed

+30
-15
lines changed

modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,14 @@
1919
import com.fasterxml.jackson.databind.ObjectMapper;
2020
import com.github.dockerjava.api.command.InspectContainerResponse;
2121
import com.github.dockerjava.api.model.ContainerNetwork;
22+
import lombok.Cleanup;
2223
import okhttp3.Credentials;
2324
import okhttp3.FormBody;
2425
import okhttp3.OkHttpClient;
2526
import okhttp3.Request;
2627
import okhttp3.RequestBody;
2728
import okhttp3.Response;
29+
import org.rnorth.ducttape.unreliables.Unreliables;
2830
import org.testcontainers.containers.GenericContainer;
2931
import org.testcontainers.containers.wait.strategy.HttpWaitStrategy;
3032
import org.testcontainers.containers.wait.strategy.WaitAllStrategy;
@@ -36,6 +38,7 @@
3638
import java.util.List;
3739
import java.util.Optional;
3840
import java.util.Set;
41+
import java.util.concurrent.TimeUnit;
3942
import java.util.stream.Collectors;
4043

4144
/**
@@ -224,7 +227,7 @@ private void waitUntilNodeIsOnline() {
224227
private void renameNode() {
225228
logger().debug("Renaming Couchbase Node from localhost to {}", getHost());
226229

227-
Response response = doHttpRequest(MGMT_PORT, "/node/controller/rename", "POST", new FormBody.Builder()
230+
@Cleanup Response response = doHttpRequest(MGMT_PORT, "/node/controller/rename", "POST", new FormBody.Builder()
228231
.add("hostname", getInternalIpAddress())
229232
.build(), false
230233
);
@@ -248,7 +251,7 @@ private void initializeServices() {
248251
}
249252
}).collect(Collectors.joining(","));
250253

251-
Response response = doHttpRequest(MGMT_PORT, "/node/controller/setupServices", "POST", new FormBody.Builder()
254+
@Cleanup Response response = doHttpRequest(MGMT_PORT, "/node/controller/setupServices", "POST", new FormBody.Builder()
252255
.add("services", services)
253256
.build(), false
254257
);
@@ -264,7 +267,7 @@ private void initializeServices() {
264267
private void configureAdminUser() {
265268
logger().debug("Configuring couchbase admin user with username: \"{}\"", username);
266269

267-
Response response = doHttpRequest(MGMT_PORT, "/settings/web", "POST", new FormBody.Builder()
270+
@Cleanup Response response = doHttpRequest(MGMT_PORT, "/settings/web", "POST", new FormBody.Builder()
268271
.add("username", username)
269272
.add("password", password)
270273
.add("port", Integer.toString(MGMT_PORT))
@@ -305,7 +308,7 @@ private void configureExternalPorts() {
305308
builder.add("ftsSSL", Integer.toString(getMappedPort(SEARCH_SSL_PORT)));
306309
}
307310

308-
final Response response = doHttpRequest(
311+
@Cleanup Response response = doHttpRequest(
309312
MGMT_PORT,
310313
"/node/controller/setupAlternateAddresses/external",
311314
"PUT",
@@ -322,7 +325,7 @@ private void configureExternalPorts() {
322325
private void configureIndexer() {
323326
logger().debug("Configuring the indexer service");
324327

325-
Response response = doHttpRequest(MGMT_PORT, "/settings/indexes", "POST", new FormBody.Builder()
328+
@Cleanup Response response = doHttpRequest(MGMT_PORT, "/settings/indexes", "POST", new FormBody.Builder()
326329
.add("storageMode", "memory_optimized")
327330
.build(), true
328331
);
@@ -339,7 +342,7 @@ private void createBuckets() {
339342
for (BucketDefinition bucket : buckets) {
340343
logger().debug("Creating bucket \"" + bucket.getName() + "\"");
341344

342-
Response response = doHttpRequest(MGMT_PORT, "/pools/default/buckets", "POST", new FormBody.Builder()
345+
@Cleanup Response response = doHttpRequest(MGMT_PORT, "/pools/default/buckets", "POST", new FormBody.Builder()
343346
.add("name", bucket.getName())
344347
.add("ramQuotaMB", Integer.toString(bucket.getQuota()))
345348
.build(), true);
@@ -353,9 +356,27 @@ private void createBuckets() {
353356
.forStatusCode(200)
354357
.waitUntilReady(this);
355358

359+
if (enabledServices.contains(CouchbaseService.QUERY)) {
360+
// If the query service is enabled, make sure that we only proceed if the query engine also
361+
// knows about the bucket in its metadata configuration.
362+
Unreliables.retryUntilTrue(1, TimeUnit.MINUTES, () -> {
363+
@Cleanup Response queryResponse = doHttpRequest(QUERY_PORT, "/query/service", "POST", new FormBody.Builder()
364+
.add("statement", "SELECT COUNT(*) > 0 as present FROM system:keyspaces WHERE name = \"" + bucket.getName() + "\"")
365+
.build(), true);
366+
367+
String body = queryResponse.body() != null ? queryResponse.body().string() : null;
368+
checkSuccessfulResponse(queryResponse, "Could not poll query service state for bucket: " + bucket.getName());
369+
370+
return Optional.of(MAPPER.readTree(body))
371+
.map(n -> n.at("/results/0/present"))
372+
.map(JsonNode::asBoolean)
373+
.orElse(false);
374+
});
375+
}
376+
356377
if (bucket.hasPrimaryIndex()) {
357378
if (enabledServices.contains(CouchbaseService.QUERY)) {
358-
Response queryResponse = doHttpRequest(QUERY_PORT, "/query/service", "POST", new FormBody.Builder()
379+
@Cleanup Response queryResponse = doHttpRequest(QUERY_PORT, "/query/service", "POST", new FormBody.Builder()
359380
.add("statement", "CREATE PRIMARY INDEX on `" + bucket.getName() + "`")
360381
.build(), true);
361382

@@ -384,14 +405,8 @@ private String getInternalIpAddress() {
384405
* @param message the message that should be part of the exception of not successful.
385406
*/
386407
private void checkSuccessfulResponse(final Response response, final String message) {
387-
try {
388-
if (!response.isSuccessful()) {
389-
throw new IllegalStateException(message + ": " + response.toString());
390-
}
391-
} finally {
392-
if (response.body() != null) {
393-
response.body().close();
394-
}
408+
if (!response.isSuccessful()) {
409+
throw new IllegalStateException(message + ": " + response.toString());
395410
}
396411
}
397412

0 commit comments

Comments
 (0)