You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@druid.apache.org by ka...@apache.org on 2025/08/30 14:46:22 UTC

(druid) branch master updated: Added limit to history in Supervisor (#18416)

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

karan 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 a8fe82db08b Added limit to history in Supervisor (#18416)
a8fe82db08b is described below

commit a8fe82db08b64658d215499234c92b60c70335d6
Author: Vadim Ogievetsky <va...@ogievetsky.com>
AuthorDate: Sat Aug 30 15:46:17 2025 +0100

    Added limit to history in Supervisor (#18416)
    
    * Added limit to history in Supervisor
    
    * update tests
    
    * cleanup API
    
    * feedback fixes
    
    * checkstyle
    
    * add validation to SupervisorResource
    
    * add provided count to error message
---
 docs/api-reference/supervisor-api.md               |  32 +++++-
 .../supervisor/CompactionSupervisorManager.java    |   2 +-
 .../overlord/supervisor/SupervisorManager.java     |   4 +-
 .../overlord/supervisor/SupervisorResource.java    |  25 ++++-
 .../http/OverlordCompactionResourceTest.java       |   2 +-
 .../overlord/supervisor/SupervisorManagerTest.java |  20 +++-
 .../supervisor/SupervisorResourceTest.java         | 112 ++++++++++++++++++---
 .../druid/metadata/MetadataSupervisorManager.java  |  10 +-
 .../metadata/SQLMetadataSupervisorManager.java     |  30 ++++--
 .../metadata/SQLMetadataSupervisorManagerTest.java |  61 ++++++++++-
 .../supervisor-history-panel.tsx                   |   2 +-
 11 files changed, 259 insertions(+), 41 deletions(-)

diff --git a/docs/api-reference/supervisor-api.md b/docs/api-reference/supervisor-api.md
index e43470f0e54..38e68d4e137 100644
--- a/docs/api-reference/supervisor-api.md
+++ b/docs/api-reference/supervisor-api.md
@@ -1827,6 +1827,11 @@ Retrieves an audit history of specs for a single supervisor.
 
 `GET` `/druid/indexer/v1/supervisor/{supervisorId}/history`
 
+#### Query parameters
+
+* `count` (optional)
+  * Type: Integer
+  * Limit the number of results to the last `n` entries. Must be greater than 0 if specified.
 
 #### Responses
 
@@ -1850,7 +1855,9 @@ Retrieves an audit history of specs for a single supervisor.
 
 #### Sample request
 
-The following example shows how to retrieve the audit history of a supervisor with the name `wikipedia_stream`.
+The following examples show how to retrieve the audit history of a supervisor with the name `wikipedia_stream`.
+
+**Get all history entries:**
 
 <Tabs>
 
@@ -1873,6 +1880,29 @@ Host: http://ROUTER_IP:ROUTER_PORT
 </TabItem>
 </Tabs>
 
+**Get last 10 history entries:**
+
+<Tabs>
+
+<TabItem value="33" label="cURL">
+
+
+```shell
+curl "http://ROUTER_IP:ROUTER_PORT/druid/indexer/v1/supervisor/wikipedia_stream/history?count=10"
+```
+
+</TabItem>
+<TabItem value="34" label="HTTP">
+
+
+```HTTP
+GET /druid/indexer/v1/supervisor/wikipedia_stream/history?count=10 HTTP/1.1
+Host: http://ROUTER_IP:ROUTER_PORT
+```
+
+</TabItem>
+</Tabs>
+
 #### Sample response
 
 <details>
diff --git a/indexing-service/src/main/java/org/apache/druid/indexing/overlord/supervisor/CompactionSupervisorManager.java b/indexing-service/src/main/java/org/apache/druid/indexing/overlord/supervisor/CompactionSupervisorManager.java
index 123eee62b44..4482b5e688a 100644
--- a/indexing-service/src/main/java/org/apache/druid/indexing/overlord/supervisor/CompactionSupervisorManager.java
+++ b/indexing-service/src/main/java/org/apache/druid/indexing/overlord/supervisor/CompactionSupervisorManager.java
@@ -177,7 +177,7 @@ public class CompactionSupervisorManager
 
     return performIfLeader(
         manager -> manager
-            .getSupervisorHistoryForId(supervisorId)
+            .getSupervisorHistoryForId(supervisorId, null)
             .stream()
             .filter(versionedSpec -> versionedSpec.getSpec() instanceof CompactionSupervisorSpec)
             .map(
diff --git a/indexing-service/src/main/java/org/apache/druid/indexing/overlord/supervisor/SupervisorManager.java b/indexing-service/src/main/java/org/apache/druid/indexing/overlord/supervisor/SupervisorManager.java
index 0ada4679a63..168b956afd2 100644
--- a/indexing-service/src/main/java/org/apache/druid/indexing/overlord/supervisor/SupervisorManager.java
+++ b/indexing-service/src/main/java/org/apache/druid/indexing/overlord/supervisor/SupervisorManager.java
@@ -299,9 +299,9 @@ public class SupervisorManager
     log.info("SupervisorManager stopped.");
   }
 
-  public List<VersionedSupervisorSpec> getSupervisorHistoryForId(String id)
+  public List<VersionedSupervisorSpec> getSupervisorHistoryForId(String id, @Nullable Integer limit) throws IllegalArgumentException
   {
-    return metadataSupervisorManager.getAllForId(id);
+    return metadataSupervisorManager.getAllForId(id, limit);
   }
 
   public Map<String, List<VersionedSupervisorSpec>> getSupervisorHistory()
diff --git a/indexing-service/src/main/java/org/apache/druid/indexing/overlord/supervisor/SupervisorResource.java b/indexing-service/src/main/java/org/apache/druid/indexing/overlord/supervisor/SupervisorResource.java
index c8b0ecff037..fdf23850580 100644
--- a/indexing-service/src/main/java/org/apache/druid/indexing/overlord/supervisor/SupervisorResource.java
+++ b/indexing-service/src/main/java/org/apache/druid/indexing/overlord/supervisor/SupervisorResource.java
@@ -533,12 +533,33 @@ public class SupervisorResource
   @Produces(MediaType.APPLICATION_JSON)
   public Response specGetHistory(
       @Context final HttpServletRequest req,
-      @PathParam("id") final String id
+      @PathParam("id") final String id,
+      @QueryParam("count") final Integer count
   )
   {
+    if (count != null && count <= 0) {
+      return Response.status(Response.Status.BAD_REQUEST)
+                     .entity(ImmutableMap.of("error", StringUtils.format("Count must be greater than zero if set (count was %d)", count)))
+                     .build();
+    }
+
     return asLeaderWithSupervisorManager(
         manager -> {
-          List<VersionedSupervisorSpec> historyForId = manager.getSupervisorHistoryForId(id);
+          List<VersionedSupervisorSpec> historyForId;
+          try {
+            historyForId = manager.getSupervisorHistoryForId(id, count);
+          }
+          catch (IllegalArgumentException e) {
+            return Response.status(Response.Status.BAD_REQUEST)
+                           .entity(
+                               ImmutableMap.of(
+                                   "error",
+                                   e.getMessage()
+                               )
+                           )
+                           .build();
+          }
+
           if (!historyForId.isEmpty()) {
             final List<VersionedSupervisorSpec> authorizedHistoryForId =
                 Lists.newArrayList(
diff --git a/indexing-service/src/test/java/org/apache/druid/indexing/overlord/http/OverlordCompactionResourceTest.java b/indexing-service/src/test/java/org/apache/druid/indexing/overlord/http/OverlordCompactionResourceTest.java
index 50bae6c8d2a..1bc00709c4b 100644
--- a/indexing-service/src/test/java/org/apache/druid/indexing/overlord/http/OverlordCompactionResourceTest.java
+++ b/indexing-service/src/test/java/org/apache/druid/indexing/overlord/http/OverlordCompactionResourceTest.java
@@ -386,7 +386,7 @@ public class OverlordCompactionResourceTest
         new VersionedSupervisorSpec(spec, "2025-01")
     );
 
-    EasyMock.expect(supervisorManager.getSupervisorHistoryForId(supervisorId))
+    EasyMock.expect(supervisorManager.getSupervisorHistoryForId(supervisorId, null))
             .andReturn(specVersions)
             .anyTimes();
     replayAll();
diff --git a/indexing-service/src/test/java/org/apache/druid/indexing/overlord/supervisor/SupervisorManagerTest.java b/indexing-service/src/test/java/org/apache/druid/indexing/overlord/supervisor/SupervisorManagerTest.java
index d9afd136654..b61c93af3c8 100644
--- a/indexing-service/src/test/java/org/apache/druid/indexing/overlord/supervisor/SupervisorManagerTest.java
+++ b/indexing-service/src/test/java/org/apache/druid/indexing/overlord/supervisor/SupervisorManagerTest.java
@@ -296,10 +296,26 @@ public class SupervisorManagerTest extends EasyMockSupport
     String id = "test-supervisor-1";
     List<VersionedSupervisorSpec> supervisorHistory = ImmutableList.of();
 
-    EasyMock.expect(metadataSupervisorManager.getAllForId(id)).andReturn(supervisorHistory);
+    EasyMock.expect(metadataSupervisorManager.getAllForId(id, null)).andReturn(supervisorHistory);
     replayAll();
 
-    List<VersionedSupervisorSpec> history = manager.getSupervisorHistoryForId(id);
+    List<VersionedSupervisorSpec> history = manager.getSupervisorHistoryForId(id, null);
+    verifyAll();
+
+    Assert.assertEquals(supervisorHistory, history);
+  }
+
+  @Test
+  public void testGetSupervisorHistoryForIdWithLimit()
+  {
+    String id = "test-supervisor-1";
+    Integer limit = 5;
+    List<VersionedSupervisorSpec> supervisorHistory = ImmutableList.of();
+
+    EasyMock.expect(metadataSupervisorManager.getAllForId(id, limit)).andReturn(supervisorHistory);
+    replayAll();
+
+    List<VersionedSupervisorSpec> history = manager.getSupervisorHistoryForId(id, limit);
     verifyAll();
 
     Assert.assertEquals(supervisorHistory, history);
diff --git a/indexing-service/src/test/java/org/apache/druid/indexing/overlord/supervisor/SupervisorResourceTest.java b/indexing-service/src/test/java/org/apache/druid/indexing/overlord/supervisor/SupervisorResourceTest.java
index 49101b34b1b..538fd4a9e78 100644
--- a/indexing-service/src/test/java/org/apache/druid/indexing/overlord/supervisor/SupervisorResourceTest.java
+++ b/indexing-service/src/test/java/org/apache/druid/indexing/overlord/supervisor/SupervisorResourceTest.java
@@ -990,23 +990,23 @@ public class SupervisorResourceTest extends EasyMockSupport
     );
 
     EasyMock.expect(taskMaster.getSupervisorManager()).andReturn(Optional.of(supervisorManager)).times(3);
-    EasyMock.expect(supervisorManager.getSupervisorHistoryForId("id1")).andReturn(versions1).times(1);
-    EasyMock.expect(supervisorManager.getSupervisorHistoryForId("id2")).andReturn(versions2).times(1);
-    EasyMock.expect(supervisorManager.getSupervisorHistoryForId("id3")).andReturn(Collections.emptyList()).times(1);
+    EasyMock.expect(supervisorManager.getSupervisorHistoryForId("id1", null)).andReturn(versions1).times(1);
+    EasyMock.expect(supervisorManager.getSupervisorHistoryForId("id2", null)).andReturn(versions2).times(1);
+    EasyMock.expect(supervisorManager.getSupervisorHistoryForId("id3", null)).andReturn(Collections.emptyList()).times(1);
     setupMockRequest();
     replayAll();
 
-    Response response = supervisorResource.specGetHistory(request, "id1");
+    Response response = supervisorResource.specGetHistory(request, "id1", null);
 
     Assert.assertEquals(200, response.getStatus());
     Assert.assertEquals(versions1, response.getEntity());
 
-    response = supervisorResource.specGetHistory(request, "id2");
+    response = supervisorResource.specGetHistory(request, "id2", null);
 
     Assert.assertEquals(200, response.getStatus());
     Assert.assertEquals(versions2, response.getEntity());
 
-    response = supervisorResource.specGetHistory(request, "id3");
+    response = supervisorResource.specGetHistory(request, "id3", null);
 
     Assert.assertEquals(404, response.getStatus());
 
@@ -1015,7 +1015,7 @@ public class SupervisorResourceTest extends EasyMockSupport
     EasyMock.expect(taskMaster.getSupervisorManager()).andReturn(Optional.absent());
     replayAll();
 
-    response = supervisorResource.specGetHistory(request, "id1");
+    response = supervisorResource.specGetHistory(request, "id1", null);
     verifyAll();
 
     Assert.assertEquals(503, response.getStatus());
@@ -1080,24 +1080,24 @@ public class SupervisorResourceTest extends EasyMockSupport
     );
 
     EasyMock.expect(taskMaster.getSupervisorManager()).andReturn(Optional.of(supervisorManager)).times(4);
-    EasyMock.expect(supervisorManager.getSupervisorHistoryForId("id1")).andReturn(versions1).times(1);
-    EasyMock.expect(supervisorManager.getSupervisorHistoryForId("id2")).andReturn(versions2).times(1);
-    EasyMock.expect(supervisorManager.getSupervisorHistoryForId("id3")).andReturn(versions3).times(1);
-    EasyMock.expect(supervisorManager.getSupervisorHistoryForId("id4")).andReturn(Collections.emptyList()).times(1);
+    EasyMock.expect(supervisorManager.getSupervisorHistoryForId("id1", null)).andReturn(versions1).times(1);
+    EasyMock.expect(supervisorManager.getSupervisorHistoryForId("id2", null)).andReturn(versions2).times(1);
+    EasyMock.expect(supervisorManager.getSupervisorHistoryForId("id3", null)).andReturn(versions3).times(1);
+    EasyMock.expect(supervisorManager.getSupervisorHistoryForId("id4", null)).andReturn(Collections.emptyList()).times(1);
     setupMockRequestForUser("notdruid");
     replayAll();
 
-    Response response = supervisorResource.specGetHistory(request, "id1");
+    Response response = supervisorResource.specGetHistory(request, "id1", null);
 
     Assert.assertEquals(200, response.getStatus());
     Assert.assertEquals(versions1, response.getEntity());
 
-    response = supervisorResource.specGetHistory(request, "id2");
+    response = supervisorResource.specGetHistory(request, "id2", null);
 
     // user is not authorized to access datasource2
     Assert.assertEquals(404, response.getStatus());
 
-    response = supervisorResource.specGetHistory(request, "id3");
+    response = supervisorResource.specGetHistory(request, "id3", null);
     Assert.assertEquals(200, response.getStatus());
     Assert.assertEquals(
         ImmutableList.of(
@@ -1125,7 +1125,7 @@ public class SupervisorResourceTest extends EasyMockSupport
         response.getEntity()
     );
 
-    response = supervisorResource.specGetHistory(request, "id4");
+    response = supervisorResource.specGetHistory(request, "id4", null);
     Assert.assertEquals(404, response.getStatus());
 
 
@@ -1134,12 +1134,92 @@ public class SupervisorResourceTest extends EasyMockSupport
     EasyMock.expect(taskMaster.getSupervisorManager()).andReturn(Optional.absent());
     replayAll();
 
-    response = supervisorResource.specGetHistory(request, "id1");
+    response = supervisorResource.specGetHistory(request, "id1", null);
     verifyAll();
 
     Assert.assertEquals(503, response.getStatus());
   }
 
+  @Test
+  public void testSpecGetHistoryWithLimit()
+  {
+    List<VersionedSupervisorSpec> versions = ImmutableList.of(
+        new VersionedSupervisorSpec(
+            new TestSupervisorSpec("id1", null, Collections.singletonList("datasource1")),
+            "v1"
+        ),
+        new VersionedSupervisorSpec(
+            new TestSupervisorSpec("id1", null, Collections.singletonList("datasource1")),
+            "v2"
+        ),
+        new VersionedSupervisorSpec(
+            new TestSupervisorSpec("id1", null, Collections.singletonList("datasource1")),
+            "v3"
+        )
+    );
+
+    List<VersionedSupervisorSpec> limitedVersions = ImmutableList.of(
+        new VersionedSupervisorSpec(
+            new TestSupervisorSpec("id1", null, Collections.singletonList("datasource1")),
+            "v1"
+        ),
+        new VersionedSupervisorSpec(
+            new TestSupervisorSpec("id1", null, Collections.singletonList("datasource1")),
+            "v2"
+        )
+    );
+
+    EasyMock.expect(taskMaster.getSupervisorManager()).andReturn(Optional.of(supervisorManager)).times(2);
+    EasyMock.expect(supervisorManager.getSupervisorHistoryForId("id1", 2)).andReturn(limitedVersions).times(1);
+    EasyMock.expect(supervisorManager.getSupervisorHistoryForId("id1", 100)).andReturn(versions).times(1);
+    setupMockRequest();
+    replayAll();
+
+    // Test with valid limit
+    Response response = supervisorResource.specGetHistory(request, "id1", 2);
+    Assert.assertEquals(200, response.getStatus());
+    Assert.assertEquals(limitedVersions, response.getEntity());
+
+    // Test with limit=0 (should return 400 Bad Request)
+    response = supervisorResource.specGetHistory(request, "id1", 0);
+    Assert.assertEquals(400, response.getStatus());
+    Assert.assertEquals(ImmutableMap.of("error", "Count must be greater than zero if set (count was 0)"), response.getEntity());
+
+    // Test with negative limit (should return 400 Bad Request)
+    response = supervisorResource.specGetHistory(request, "id1", -1);
+    Assert.assertEquals(400, response.getStatus());
+    Assert.assertEquals(ImmutableMap.of("error", "Count must be greater than zero if set (count was -1)"), response.getEntity());
+
+    // Test with limit larger than available history
+    response = supervisorResource.specGetHistory(request, "id1", 100);
+    Assert.assertEquals(200, response.getStatus());
+    Assert.assertEquals(versions, response.getEntity());
+
+    verifyAll();
+  }
+
+  @Test
+  public void testSpecGetHistoryWithNullLimit()
+  {
+    List<VersionedSupervisorSpec> versions = ImmutableList.of(
+        new VersionedSupervisorSpec(
+            new TestSupervisorSpec("id1", null, Collections.singletonList("datasource1")),
+            "v1"
+        )
+    );
+
+    EasyMock.expect(taskMaster.getSupervisorManager()).andReturn(Optional.of(supervisorManager)).times(1);
+    EasyMock.expect(supervisorManager.getSupervisorHistoryForId("id1", null)).andReturn(versions).times(1);
+    setupMockRequest();
+    replayAll();
+
+    Response response = supervisorResource.specGetHistory(request, "id1", null);
+    Assert.assertEquals(200, response.getStatus());
+    Assert.assertEquals(versions, response.getEntity());
+
+    verifyAll();
+  }
+
   @Test
   public void testReset()
   {
diff --git a/server/src/main/java/org/apache/druid/metadata/MetadataSupervisorManager.java b/server/src/main/java/org/apache/druid/metadata/MetadataSupervisorManager.java
index 70b25d95275..298e260e0e6 100644
--- a/server/src/main/java/org/apache/druid/metadata/MetadataSupervisorManager.java
+++ b/server/src/main/java/org/apache/druid/metadata/MetadataSupervisorManager.java
@@ -22,6 +22,7 @@ package org.apache.druid.metadata;
 import org.apache.druid.indexing.overlord.supervisor.SupervisorSpec;
 import org.apache.druid.indexing.overlord.supervisor.VersionedSupervisorSpec;
 
+import javax.annotation.Nullable;
 import java.util.List;
 import java.util.Map;
 
@@ -33,7 +34,14 @@ public interface MetadataSupervisorManager
 
   Map<String, List<VersionedSupervisorSpec>> getAll();
 
-  List<VersionedSupervisorSpec> getAllForId(String id);
+  /**
+   * Get supervisor history for a given supervisor ID with an optional limit
+   *
+   * @param id the supervisor ID
+   * @param limit maximum number of history entries to return (null for all entries)
+   * @return list of versioned supervisor specs for the given ID
+   */
+  List<VersionedSupervisorSpec> getAllForId(String id, @Nullable Integer limit);
 
   /**
    * Return latest supervisors (both active and terminated)
diff --git a/server/src/main/java/org/apache/druid/metadata/SQLMetadataSupervisorManager.java b/server/src/main/java/org/apache/druid/metadata/SQLMetadataSupervisorManager.java
index 5564d715792..2882286de65 100644
--- a/server/src/main/java/org/apache/druid/metadata/SQLMetadataSupervisorManager.java
+++ b/server/src/main/java/org/apache/druid/metadata/SQLMetadataSupervisorManager.java
@@ -138,19 +138,29 @@ public class SQLMetadataSupervisorManager implements MetadataSupervisorManager
   }
 
   @Override
-  public List<VersionedSupervisorSpec> getAllForId(String id)
+  public List<VersionedSupervisorSpec> getAllForId(String id, @Nullable Integer limit) throws IllegalArgumentException
   {
+    if (limit != null && limit <= 0) {
+      throw new IllegalArgumentException("Limit must be greater than zero if set");
+    }
+
     return ImmutableList.copyOf(
         dbi.withHandle(
-            (HandleCallback<List<VersionedSupervisorSpec>>) handle -> handle.createQuery(
-                StringUtils.format(
-                    "SELECT id, spec_id, created_date, payload FROM %1$s WHERE spec_id = :spec_id ORDER BY id DESC",
-                    getSupervisorsTable()
-                )
-            )
-            .bind("spec_id", id)
-            .map((index, r, ctx) -> createVersionSupervisorSpecFromResponse(r))
-            .list()
+            (HandleCallback<List<VersionedSupervisorSpec>>) handle -> {
+              String query = StringUtils.format(
+                  "SELECT id, spec_id, created_date, payload FROM %1$s WHERE spec_id = :spec_id ORDER BY id DESC",
+                  getSupervisorsTable()
+              );
+              
+              if (limit != null) {
+                query += " " + connector.limitClause(limit);
+              }
+              
+              return handle.createQuery(query)
+                           .bind("spec_id", id)
+                           .map((index, r, ctx) -> createVersionSupervisorSpecFromResponse(r))
+                           .list();
+            }
         )
     );
   }
diff --git a/server/src/test/java/org/apache/druid/metadata/SQLMetadataSupervisorManagerTest.java b/server/src/test/java/org/apache/druid/metadata/SQLMetadataSupervisorManagerTest.java
index ae931697476..3f9297cdb9b 100644
--- a/server/src/test/java/org/apache/druid/metadata/SQLMetadataSupervisorManagerTest.java
+++ b/server/src/test/java/org/apache/druid/metadata/SQLMetadataSupervisorManagerTest.java
@@ -220,8 +220,8 @@ public class SQLMetadataSupervisorManagerTest
     final Map<String, String> data2rev1 = ImmutableMap.of("key2-1", "value2-1-1", "key2-2", "value2-2-1");
     final Map<String, String> data2rev2 = ImmutableMap.of("key2-3", "value2-3-2", "key2-4", "value2-4-2");
 
-    Assert.assertTrue(supervisorManager.getAllForId(supervisor1).isEmpty());
-    Assert.assertTrue(supervisorManager.getAllForId(supervisor2).isEmpty());
+    Assert.assertTrue(supervisorManager.getAllForId(supervisor1, null).isEmpty());
+    Assert.assertTrue(supervisorManager.getAllForId(supervisor2, null).isEmpty());
 
     // add 2 supervisors, with revisions
     supervisorManager.insert(supervisor1, new TestSupervisorSpec(supervisor1, data1rev1));
@@ -230,8 +230,8 @@ public class SQLMetadataSupervisorManagerTest
     supervisorManager.insert(supervisor2, new TestSupervisorSpec(supervisor2, data2rev1));
     supervisorManager.insert(supervisor2, new TestSupervisorSpec(supervisor2, data2rev2));
 
-    List<VersionedSupervisorSpec> supervisor1Specs = supervisorManager.getAllForId(supervisor1);
-    List<VersionedSupervisorSpec> supervisor2Specs = supervisorManager.getAllForId(supervisor2);
+    List<VersionedSupervisorSpec> supervisor1Specs = supervisorManager.getAllForId(supervisor1, null);
+    List<VersionedSupervisorSpec> supervisor2Specs = supervisorManager.getAllForId(supervisor2, null);
 
     Assert.assertEquals(3, supervisor1Specs.size());
     Assert.assertEquals(2, supervisor2Specs.size());
@@ -310,6 +310,59 @@ public class SQLMetadataSupervisorManagerTest
     Assert.assertTrue(actual.containsKey(supervisor1));
   }
 
+  @Test
+  public void testGetAllForIdWithLimit()
+  {
+    final String supervisor1 = "test-supervisor-1";
+    final Map<String, String> data1rev1 = ImmutableMap.of("key1-1", "value1-1-1", "key1-2", "value1-2-1");
+    final Map<String, String> data1rev2 = ImmutableMap.of("key1-1", "value1-1-2", "key1-2", "value1-2-2");
+    final Map<String, String> data1rev3 = ImmutableMap.of("key1-1", "value1-1-3", "key1-2", "value1-2-3");
+
+    Assert.assertTrue(supervisorManager.getAll().isEmpty());
+
+    // Insert 3 versions
+    supervisorManager.insert(supervisor1, new TestSupervisorSpec(supervisor1, data1rev1));
+    supervisorManager.insert(supervisor1, new TestSupervisorSpec(supervisor1, data1rev2));
+    supervisorManager.insert(supervisor1, new TestSupervisorSpec(supervisor1, data1rev3));
+
+    // Test with limit=2
+    List<VersionedSupervisorSpec> limitedResults = supervisorManager.getAllForId(supervisor1, 2);
+    Assert.assertEquals(2, limitedResults.size());
+    // Results should be in descending order (newest first)
+    Assert.assertEquals(data1rev3, ((TestSupervisorSpec) limitedResults.get(0).getSpec()).getData());
+    Assert.assertEquals(data1rev2, ((TestSupervisorSpec) limitedResults.get(1).getSpec()).getData());
+
+    // Test with limit=1
+    limitedResults = supervisorManager.getAllForId(supervisor1, 1);
+    Assert.assertEquals(1, limitedResults.size());
+    Assert.assertEquals(data1rev3, ((TestSupervisorSpec) limitedResults.get(0).getSpec()).getData());
+
+    // Test with limit=0 (should throw exception)
+    try {
+      supervisorManager.getAllForId(supervisor1, 0);
+      Assert.fail("Expected IllegalArgumentException for limit=0");
+    }
+    catch (IllegalArgumentException e) {
+      Assert.assertEquals("Limit must be greater than zero if set", e.getMessage());
+    }
+
+    // Test with limit=null (should return all)
+    List<VersionedSupervisorSpec> allResults = supervisorManager.getAllForId(supervisor1, null);
+    Assert.assertEquals(3, allResults.size());
+
+    // Test with limit larger than available records
+    limitedResults = supervisorManager.getAllForId(supervisor1, 10);
+    Assert.assertEquals(3, limitedResults.size());
+
+    // Test with negative limit (should throw exception)
+    try {
+      supervisorManager.getAllForId(supervisor1, -1);
+      Assert.fail("Expected IllegalArgumentException for limit=-1");
+    }
+    catch (IllegalArgumentException e) {
+      Assert.assertEquals("Limit must be greater than zero if set", e.getMessage());
+    }
+  }
 
   private static class BadSupervisorSpec implements SupervisorSpec
   {
diff --git a/web-console/src/components/supervisor-history-panel/supervisor-history-panel.tsx b/web-console/src/components/supervisor-history-panel/supervisor-history-panel.tsx
index fabc0882f56..559c48539c2 100644
--- a/web-console/src/components/supervisor-history-panel/supervisor-history-panel.tsx
+++ b/web-console/src/components/supervisor-history-panel/supervisor-history-panel.tsx
@@ -51,7 +51,7 @@ export const SupervisorHistoryPanel = React.memo(function SupervisorHistoryPanel
     processQuery: async (supervisorId, cancelToken) => {
       return (
         await getApiArray<SupervisorHistoryEntry>(
-          `/druid/indexer/v1/supervisor/${Api.encodePath(supervisorId)}/history`,
+          `/druid/indexer/v1/supervisor/${Api.encodePath(supervisorId)}/history?count=100`,
           cancelToken,
         )
       ).map(vs => deepSet(vs, 'spec', cleanSpec(vs.spec)));


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org
For additional commands, e-mail: commits-help@druid.apache.org