Kangs-Claw commented on code in PR #10046:
URL: https://github.com/apache/gravitino/pull/10046#discussion_r2876383403


##########
integration-test-common/src/test/java/org/apache/gravitino/integration/test/container/DorisContainer.java:
##########
@@ -63,78 +84,136 @@ protected DorisContainer(
       Map<String, String> envVars,
       Optional<Network> network) {
     super(image, hostName, ports, extraHosts, filesToMount, envVars, network);
-  }
 
-  @Override
-  protected void setupContainer() {
-    super.setupContainer();
-    withLogConsumer(new PrintingContainerLog(format("%-14s| ", 
"DorisContainer")));
-    withStartupTimeout(Duration.ofMinutes(5));
+    String dir = System.getenv("GRAVITINO_ROOT_DIR");
+    if (dir == null || dir.isEmpty()) {
+      throw new RuntimeException("GRAVITINO_ROOT_DIR is not set");
+    }
+    String composeFile =
+        ITUtils.joinPath(
+            dir, "integration-test-common", "doris-docker-script", 
"docker-compose.yaml");
+
+    String effectiveImage =
+        (DEFAULT_IMAGE != null && !DEFAULT_IMAGE.isEmpty()) ? DEFAULT_IMAGE : 
image;
+    Preconditions.checkArgument(
+        effectiveImage != null && !effectiveImage.isEmpty(),
+        "Doris Docker image must be configured via 
GRAVITINO_CI_DORIS_DOCKER_IMAGE or "
+            + "DorisContainer builder image");
+
+    composeContainer =
+        new ComposeContainer(new File(composeFile))
+            .withEnv("GRAVITINO_CI_DORIS_DOCKER_IMAGE", effectiveImage)
+            .withExposedService(
+                FE_SERVICE,
+                FE_MYSQL_PORT,
+                
Wait.forListeningPort().withStartupTimeout(Duration.ofMinutes(3)))
+            .withExposedService(FE_SERVICE, FE_HTTP_PORT)
+            .withScaledService(BE_SERVICE, BE_SCALE)
+            .withStartupTimeout(Duration.ofMinutes(5))
+            .withTailChildContainers(true)
+            .withLocalCompose(true);
+
+    // Expose ports for each BE instance (1-indexed)
+    for (int i = 1; i <= BE_SCALE; i++) {
+      composeContainer
+          .withExposedService(
+              BE_SERVICE,
+              i,
+              BE_HEARTBEAT_PORT,
+              
Wait.forListeningPort().withStartupTimeout(Duration.ofMinutes(3)))
+          .withExposedService(BE_SERVICE, i, BE_WEBSERVER_PORT);
+    }
   }
 
   @Override
   public void start() {
-    super.start();
+    composeContainer.start();
+    resolveFeIpAddress();
     Preconditions.check("Doris container startup failed!", 
checkContainerStatus(5));
     Preconditions.check("Doris container password change failed!", 
changePassword());
   }
 
   @Override
   public void close() {
     copyDorisLog();
-    super.close();
+    if (composeContainer != null) {
+      composeContainer.stop();
+    }
   }
 
   private void copyDorisLog() {
     try {
-      // stop Doris container
       String destPath = System.getenv("IT_PROJECT_DIR");
-      LOG.info("Copy doris log file to {}", destPath);
-
-      String feTarPath = "/doris-be.tar";
-      String beTarPath = "/doris-fe.tar";
-
-      // Pack the jar files
-      container.execInContainer("tar", "cf", feTarPath, DORIS_BE_PATH);
-      container.execInContainer("tar", "cf", beTarPath, DORIS_FE_PATH);
-
-      container.copyFileFromContainer(feTarPath, destPath + File.separator + 
"doris-be.tar");
-      container.copyFileFromContainer(beTarPath, destPath + File.separator + 
"doris-fe.tar");
+      if (destPath == null || destPath.isEmpty()) {
+        LOG.warn("IT_PROJECT_DIR is not set, skipping Doris log copy");
+        return;
+      }
+      LOG.info("Copy doris log files to {}", destPath);
+      copyContainerLog(FE_SERVICE, DORIS_FE_PATH, destPath, "doris-fe");
+      for (int i = 1; i <= BE_SCALE; i++) {
+        copyContainerLog(BE_SERVICE + "-" + i, DORIS_BE_PATH, destPath, 
"doris-be-" + i);
+      }
     } catch (Exception e) {
-      LOG.error("Failed to copy container log to local", e);
+      LOG.error("Failed to copy Doris container logs to local", e);
+    }
+  }
+
+  private void copyContainerLog(String serviceName, String logPath, String 
destPath, String tarName)
+      throws Exception {
+    Optional<ContainerState> container = 
composeContainer.getContainerByServiceName(serviceName);
+    if (container.isPresent()) {
+      String tarPath = "/" + tarName + ".tar";
+      container.get().execInContainer("tar", "cf", tarPath, logPath);
+      container.get().copyFileFromContainer(tarPath, destPath + File.separator 
+ tarName + ".tar");
+    } else {
+      LOG.warn("Doris {} container not found, skipping log copy", serviceName);
     }
   }
 
+  @Override
+  public String getContainerIpAddress() {
+    return feIpAddress;
+  }
+
   @Override
   protected boolean checkContainerStatus(int retryLimit) {
-    String dorisJdbcUrl = format("jdbc:mysql://%s:%d/", 
getContainerIpAddress(), FE_MYSQL_PORT);
-    LOG.info("Doris url is " + dorisJdbcUrl);
+    String dorisJdbcUrl = format("jdbc:mysql://%s:%d/", feIpAddress, 
FE_MYSQL_PORT);
+    LOG.info("Doris JDBC url is {}", dorisJdbcUrl);
 
     await()
-        .atMost(30, TimeUnit.SECONDS)
-        .pollInterval(30 / retryLimit, TimeUnit.SECONDS)
+        .atMost(120, TimeUnit.SECONDS)
+        .pollInterval(120 / retryLimit, TimeUnit.SECONDS)
         .until(
             () -> {
               try (Connection connection =
                       DriverManager.getConnection(dorisJdbcUrl, USER_NAME, "");
                   Statement statement = connection.createStatement()) {
 
-                // execute `SHOW PROC '/backends';` to check if backends is 
ready
+                // execute `SHOW PROC '/backends';` to check if all backends 
are ready
                 String query = "SHOW PROC '/backends';";
+                int aliveCount = 0;
                 try (ResultSet resultSet = statement.executeQuery(query)) {
                   while (resultSet.next()) {
                     String alive = resultSet.getString("Alive");
                     String totalCapacity = 
resultSet.getString("TotalCapacity");
                     float totalCapacityFloat = 
Float.parseFloat(totalCapacity.split(" ")[0]);
 
-                    // alive should be true and totalCapacity should not be 
0.000
                     if (alive.equalsIgnoreCase("true") && totalCapacityFloat > 
0.0f) {
-                      LOG.info("Doris container startup success!");
-                      return true;
+                      aliveCount++;
                     }
                   }
                 }
-                LOG.info("Doris container is not ready yet!");
+
+                if (aliveCount >= BE_SCALE) {

Review Comment:
   Good question! In theory, `aliveCount` should not exceed `BE_SCALE` since we 
only start 3 BE containers via `withScaledService(BE_SERVICE, BE_SCALE)`. 
However, using `>=` instead of `==` is more robust because:
   
   1. It handles edge cases where extra backends might be present from previous 
test runs
   2. It's more defensive programming - if somehow more backends appear, the 
check still passes
   3. It aligns with the intent: "we need at least BE_SCALE backends alive"
   
   So while it's unlikely to happen in normal circumstances, the `>=` check is 
safer and more correct.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to