This is an automated email from the ASF dual-hosted git repository.

gian pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/druid.git


The following commit(s) were added to refs/heads/master by this push:
     new 15b4003ac4b Add durationMs to Dart query reports. (#19169)
15b4003ac4b is described below

commit 15b4003ac4b3318eccc1ef085e69bc56d3af25f1
Author: Gian Merlino <[email protected]>
AuthorDate: Mon Mar 16 22:22:00 2026 -0700

    Add durationMs to Dart query reports. (#19169)
---
 .../embedded/msq/EmbeddedDartReportApiTest.java    |  3 ++
 .../dart/controller/DartControllerRegistry.java    | 33 +++++++++++++++++--
 .../msq/dart/controller/http/DartQueryInfo.java    | 38 +++++++++++++++++++---
 .../dart/controller/http/DartQueryInfoTest.java    |  3 +-
 .../dart/controller/http/DartSqlResourceTest.java  |  9 +++--
 .../dart/controller/sql/DartSqlClientImplTest.java |  9 +++--
 6 files changed, 80 insertions(+), 15 deletions(-)

diff --git 
a/embedded-tests/src/test/java/org/apache/druid/testing/embedded/msq/EmbeddedDartReportApiTest.java
 
b/embedded-tests/src/test/java/org/apache/druid/testing/embedded/msq/EmbeddedDartReportApiTest.java
index c0787c2e21c..c6915d859fd 100644
--- 
a/embedded-tests/src/test/java/org/apache/druid/testing/embedded/msq/EmbeddedDartReportApiTest.java
+++ 
b/embedded-tests/src/test/java/org/apache/druid/testing/embedded/msq/EmbeddedDartReportApiTest.java
@@ -241,6 +241,8 @@ public class EmbeddedDartReportApiTest extends 
EmbeddedClusterTestBase
     Assertions.assertEquals(sql, queryInfo.getSql());
     Assertions.assertEquals(sqlQueryId, queryInfo.getSqlQueryId());
     Assertions.assertNotNull(queryInfo.getDartQueryId());
+    Assertions.assertNotNull(queryInfo.getDurationMs(), "durationMs should be 
set for completed query");
+    Assertions.assertTrue(queryInfo.getDurationMs() >= 0, "durationMs should 
be non-negative");
 
     // Verify the report is an MSQTaskReport
     Assertions.assertInstanceOf(TaskReport.ReportMap.class, 
reportResponse.getReportMap());
@@ -343,6 +345,7 @@ public class EmbeddedDartReportApiTest extends 
EmbeddedClusterTestBase
       Assertions.assertEquals(sqlQueryId, queryInfo.getSqlQueryId());
       Assertions.assertEquals(sql, queryInfo.getSql());
       Assertions.assertNotNull(queryInfo.getDartQueryId());
+      Assertions.assertNotNull(queryInfo.getDurationMs());
       Assertions.assertInstanceOf(TaskReport.ReportMap.class, 
report.getReportMap());
       Assertions.assertInstanceOf(MSQTaskReport.class, 
report.getReportMap().get(MSQTaskReport.REPORT_KEY));
     }
diff --git 
a/multi-stage-query/src/main/java/org/apache/druid/msq/dart/controller/DartControllerRegistry.java
 
b/multi-stage-query/src/main/java/org/apache/druid/msq/dart/controller/DartControllerRegistry.java
index 9beab028d1c..f1d1e4e1b76 100644
--- 
a/multi-stage-query/src/main/java/org/apache/druid/msq/dart/controller/DartControllerRegistry.java
+++ 
b/multi-stage-query/src/main/java/org/apache/druid/msq/dart/controller/DartControllerRegistry.java
@@ -32,6 +32,9 @@ import 
org.apache.druid.java.util.common.lifecycle.LifecycleStop;
 import org.apache.druid.msq.dart.controller.http.DartQueryInfo;
 import org.apache.druid.msq.dart.guice.DartControllerConfig;
 import org.apache.druid.msq.exec.Controller;
+import org.apache.druid.msq.indexing.report.MSQStatusReport;
+import org.apache.druid.msq.indexing.report.MSQTaskReport;
+import org.apache.druid.msq.indexing.report.MSQTaskReportPayload;
 import org.joda.time.Period;
 
 import javax.annotation.Nullable;
@@ -166,7 +169,7 @@ public class DartControllerRegistry
         completeReports.put(
             dartQueryId,
             new QueryInfoAndReport(
-                DartQueryInfo.fromControllerHolder(holder),
+                
createQueryInfo(holder).withDurationMs(getDurationMs(completeReport)),
                 completeReport,
                 DateTimes.nowUtc()
             )
@@ -252,6 +255,14 @@ public class DartControllerRegistry
     return retVal;
   }
 
+  /**
+   * Create {@link DartQueryInfo} from a {@link ControllerHolder}.
+   */
+  protected DartQueryInfo createQueryInfo(final ControllerHolder 
controllerHolder)
+  {
+    return DartQueryInfo.fromControllerHolder(controllerHolder);
+  }
+
   /**
    * Removes reports that have exceeded {@link 
DartControllerConfig#getMaxRetainedReportDuration()}.
    */
@@ -275,12 +286,28 @@ public class DartControllerRegistry
     }
   }
 
-  private static QueryInfoAndReport getQueryDetails(final ControllerHolder 
controllerHolder)
+  private QueryInfoAndReport getQueryDetails(final ControllerHolder 
controllerHolder)
   {
     return new QueryInfoAndReport(
-        DartQueryInfo.fromControllerHolder(controllerHolder),
+        createQueryInfo(controllerHolder),
         controllerHolder.getController().liveReports(),
         DateTimes.nowUtc()
     );
   }
+
+  /**
+   * Extracts durationMs from the {@link MSQStatusReport} within a {@link 
TaskReport.ReportMap}, if present.
+   */
+  @Nullable
+  private static Long getDurationMs(final TaskReport.ReportMap reportMap)
+  {
+    final TaskReport msqReport = reportMap.get(MSQTaskReport.REPORT_KEY);
+    if (msqReport instanceof MSQTaskReport) {
+      final MSQTaskReportPayload payload = ((MSQTaskReport) 
msqReport).getPayload();
+      if (payload != null && payload.getStatus() != null) {
+        return payload.getStatus().getDurationMs();
+      }
+    }
+    return null;
+  }
 }
diff --git 
a/multi-stage-query/src/main/java/org/apache/druid/msq/dart/controller/http/DartQueryInfo.java
 
b/multi-stage-query/src/main/java/org/apache/druid/msq/dart/controller/http/DartQueryInfo.java
index ca6f3861d95..9902b86239f 100644
--- 
a/multi-stage-query/src/main/java/org/apache/druid/msq/dart/controller/http/DartQueryInfo.java
+++ 
b/multi-stage-query/src/main/java/org/apache/druid/msq/dart/controller/http/DartQueryInfo.java
@@ -32,6 +32,7 @@ import org.apache.druid.sql.http.GetQueriesResponse;
 import org.apache.druid.sql.http.QueryInfo;
 import org.joda.time.DateTime;
 
+import javax.annotation.Nullable;
 import java.util.Objects;
 
 /**
@@ -48,6 +49,9 @@ public class DartQueryInfo implements QueryInfo
   private final DateTime startTime;
   private final String state;
 
+  @Nullable
+  private final Long durationMs;
+
   @JsonCreator
   public DartQueryInfo(
       @JsonProperty("sqlQueryId") final String sqlQueryId,
@@ -57,7 +61,8 @@ public class DartQueryInfo implements QueryInfo
       @JsonProperty("authenticator") final String authenticator,
       @JsonProperty("identity") final String identity,
       @JsonProperty("startTime") final DateTime startTime,
-      @JsonProperty("state") final String state
+      @JsonProperty("state") final String state,
+      @JsonProperty("durationMs") @Nullable final Long durationMs
   )
   {
     this.sqlQueryId = Preconditions.checkNotNull(sqlQueryId, "sqlQueryId");
@@ -68,6 +73,7 @@ public class DartQueryInfo implements QueryInfo
     this.identity = identity;
     this.startTime = startTime;
     this.state = state;
+    this.durationMs = durationMs;
   }
 
   public static DartQueryInfo fromControllerHolder(final ControllerHolder 
holder)
@@ -80,7 +86,8 @@ public class DartQueryInfo implements QueryInfo
         holder.getAuthenticationResult().getAuthenticatedBy(),
         holder.getAuthenticationResult().getIdentity(),
         holder.getStartTime(),
-        holder.getState().getStatusString()
+        holder.getState().getStatusString(),
+        null
     );
   }
 
@@ -152,6 +159,17 @@ public class DartQueryInfo implements QueryInfo
     return startTime;
   }
 
+  /**
+   * Duration of this query in milliseconds, or null if not yet known.
+   */
+  @Nullable
+  @JsonProperty
+  @JsonInclude(JsonInclude.Include.NON_NULL)
+  public Long getDurationMs()
+  {
+    return durationMs;
+  }
+
   @Override
   @JsonProperty
   public String state()
@@ -171,12 +189,20 @@ public class DartQueryInfo implements QueryInfo
     return dartQueryId;
   }
 
+  /**
+   * Returns a copy of this instance with the given durationMs.
+   */
+  public DartQueryInfo withDurationMs(@Nullable final Long durationMs)
+  {
+    return new DartQueryInfo(sqlQueryId, dartQueryId, sql, controllerHost, 
authenticator, identity, startTime, state, durationMs);
+  }
+
   /**
    * Returns a copy of this instance with {@link #getAuthenticator()} and 
{@link #getIdentity()} nulled.
    */
   public DartQueryInfo withoutAuthenticationResult()
   {
-    return new DartQueryInfo(sqlQueryId, dartQueryId, sql, controllerHost, 
null, null, startTime, state);
+    return new DartQueryInfo(sqlQueryId, dartQueryId, sql, controllerHost, 
null, null, startTime, state, durationMs);
   }
 
   @Override
@@ -196,13 +222,14 @@ public class DartQueryInfo implements QueryInfo
            && Objects.equals(authenticator, that.authenticator)
            && Objects.equals(identity, that.identity)
            && Objects.equals(startTime, that.startTime)
-           && Objects.equals(state, that.state);
+           && Objects.equals(state, that.state)
+           && Objects.equals(durationMs, that.durationMs);
   }
 
   @Override
   public int hashCode()
   {
-    return Objects.hash(sqlQueryId, dartQueryId, sql, controllerHost, 
authenticator, identity, startTime, state);
+    return Objects.hash(sqlQueryId, dartQueryId, sql, controllerHost, 
authenticator, identity, startTime, state, durationMs);
   }
 
   @Override
@@ -217,6 +244,7 @@ public class DartQueryInfo implements QueryInfo
            ", identity='" + identity + '\'' +
            ", startTime=" + startTime +
            ", state='" + state + '\'' +
+           ", durationMs=" + durationMs +
            '}';
   }
 }
diff --git 
a/multi-stage-query/src/test/java/org/apache/druid/msq/dart/controller/http/DartQueryInfoTest.java
 
b/multi-stage-query/src/test/java/org/apache/druid/msq/dart/controller/http/DartQueryInfoTest.java
index 7c09f0a170e..8119f5b1627 100644
--- 
a/multi-stage-query/src/test/java/org/apache/druid/msq/dart/controller/http/DartQueryInfoTest.java
+++ 
b/multi-stage-query/src/test/java/org/apache/druid/msq/dart/controller/http/DartQueryInfoTest.java
@@ -44,7 +44,8 @@ public class DartQueryInfoTest
         "",
         "",
         DateTimes.of("2000"),
-        StandardQueryState.RUNNING
+        StandardQueryState.RUNNING,
+        1000L
     );
     ObjectMapper jsonMapper = new DefaultObjectMapper().registerModules(new 
DartWorkerModule().getJacksonModules());
     byte[] bytes = jsonMapper.writeValueAsBytes(dartQueryInfo);
diff --git 
a/multi-stage-query/src/test/java/org/apache/druid/msq/dart/controller/http/DartSqlResourceTest.java
 
b/multi-stage-query/src/test/java/org/apache/druid/msq/dart/controller/http/DartSqlResourceTest.java
index 0b77461d178..1b2d7d8a547 100644
--- 
a/multi-stage-query/src/test/java/org/apache/druid/msq/dart/controller/http/DartSqlResourceTest.java
+++ 
b/multi-stage-query/src/test/java/org/apache/druid/msq/dart/controller/http/DartSqlResourceTest.java
@@ -381,7 +381,8 @@ public class DartSqlResourceTest extends MSQTestBase
         AUTHENTICATOR_NAME,
         DIFFERENT_REGULAR_USER_NAME,
         DateTimes.of("2001"),
-        StandardQueryState.RUNNING
+        StandardQueryState.RUNNING,
+        null
     );
     Mockito.when(dartSqlClient.getRunningQueries(true, false))
            .thenReturn(Futures.immediateFuture(new 
GetQueriesResponse(Collections.singletonList(remoteQueryInfo))));
@@ -449,7 +450,8 @@ public class DartSqlResourceTest extends MSQTestBase
         AUTHENTICATOR_NAME,
         DIFFERENT_REGULAR_USER_NAME,
         DateTimes.of("2000"),
-        StandardQueryState.RUNNING
+        StandardQueryState.RUNNING,
+        null
     );
     Mockito.when(dartSqlClient.getRunningQueries(true, false))
            .thenReturn(Futures.immediateFuture(new 
GetQueriesResponse(Collections.singletonList(remoteQueryInfo))));
@@ -486,7 +488,8 @@ public class DartSqlResourceTest extends MSQTestBase
         AUTHENTICATOR_NAME,
         DIFFERENT_REGULAR_USER_NAME,
         DateTimes.of("2000"),
-        StandardQueryState.RUNNING
+        StandardQueryState.RUNNING,
+        null
     );
     Mockito.when(dartSqlClient.getRunningQueries(true, false))
            .thenReturn(Futures.immediateFuture(new 
GetQueriesResponse(Collections.singletonList(remoteQueryInfo))));
diff --git 
a/multi-stage-query/src/test/java/org/apache/druid/msq/dart/controller/sql/DartSqlClientImplTest.java
 
b/multi-stage-query/src/test/java/org/apache/druid/msq/dart/controller/sql/DartSqlClientImplTest.java
index cdd1276c481..258dd370c6a 100644
--- 
a/multi-stage-query/src/test/java/org/apache/druid/msq/dart/controller/sql/DartSqlClientImplTest.java
+++ 
b/multi-stage-query/src/test/java/org/apache/druid/msq/dart/controller/sql/DartSqlClientImplTest.java
@@ -74,7 +74,8 @@ public class DartSqlClientImplTest
                 "",
                 "",
                 DateTimes.of("2000"),
-                ControllerHolder.State.RUNNING.toString()
+                ControllerHolder.State.RUNNING.toString(),
+                null
             )
         )
     );
@@ -103,7 +104,8 @@ public class DartSqlClientImplTest
                 "",
                 "",
                 DateTimes.of("2000"),
-                ControllerHolder.State.RUNNING.toString()
+                ControllerHolder.State.RUNNING.toString(),
+                null
             )
         )
     );
@@ -132,7 +134,8 @@ public class DartSqlClientImplTest
                 "",
                 "",
                 DateTimes.of("2000"),
-                ControllerHolder.State.RUNNING.toString()
+                ControllerHolder.State.RUNNING.toString(),
+                null
             )
         )
     );


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to