FrankChen021 commented on code in PR #20706:
URL: https://github.com/apache/druid/pull/20706#discussion_r4365469403


##########
indexing-service/src/main/java/org/apache/druid/indexing/seekablestream/supervisor/SeekableStreamSupervisor.java:
##########
@@ -4066,17 +4072,15 @@ void maybeScaleDuringTaskRollover()
             "Updating taskCount for supervisor[%s] from [%d] to [%d] during 
rollover.",
             supervisorId, currentTaskCount, rolloverTaskCount
         );
-        isScalingTasksOnRollover.set(true);
-        try {
-          new DynamicAllocationTasksNotice(
-              () -> rolloverTaskCount,
-              () -> {},
-              emitter
-          ).handle();
-        }
-        finally {
-          isScalingTasksOnRollover.set(false);
-        }
+        handleDynamicAllocationTasksNotice(
+            () -> rolloverTaskCount,
+            () -> {},
+            true
+        );
+      } else {
+        // Reset last scale time even if taskCount is not being changed.
+        // Otherwise, we might have a scaling event right after the task 
rollover.
+        dynamicTriggerLastScaleRunTime = System.currentTimeMillis();

Review Comment:
   [P2] Do not start a cooldown when rollover count cannot be computed
   
   **Finding:** LagBasedAutoScaler inherits 
SupervisorTaskAutoScaler.computeTaskCountForRollover(), which returns 
CANNOT_COMPUTE (-1), and CostBasedAutoScaler returns the same sentinel before 
metrics are available. This else branch still stamps 
dynamicTriggerLastScaleRunTime; with minScaleUpDelay or minScaleDownDelay 
longer than taskDuration, no rollover scale occurs and the next regular action 
is blocked for a full cooldown from rollover, even when no prior scale 
happened. That defeats the low-sensitivity behavior described in the PR for 
LagBasedAutoScaler and can leave ingestion under-resourced while lag grows.
   
   **Suggestion:** Distinguish CANNOT_COMPUTE from a valid same-count 
recommendation and reset the timestamp only after a valid rollover evaluation; 
implement a rollover recommendation for LagBasedAutoScaler if rollover scaling 
is intended for both strategies.



##########
indexing-service/src/test/java/org/apache/druid/indexing/seekablestream/supervisor/autoscaler/LagBasedAutoScalerTest.java:
##########
@@ -121,7 +121,7 @@ public void 
testReturnsUnclampedScaleInStepEvenWhenCurrentIsAboveMax()
 
   private LagBasedAutoScaler createAutoScaler()
   {
-    return new LagBasedAutoScaler(mockSupervisor, config, mockSpec, 
mockEmitter);
+    return new LagBasedAutoScaler(mockSupervisor, config, mockSpec);

Review Comment:
   [P1] Remove the stale emitter import left by this constructor change
   
   **Finding:** After this constructor change, LagBasedAutoScalerTest no longer 
uses mockEmitter, but the ServiceEmitter import and field initialization remain 
in the test. Druid's validate Checkstyle configuration enables UnusedImports 
for test sources, so the indexing-service build will fail before running tests.
   
   **Suggestion:** Delete the unused ServiceEmitter import and the mockEmitter 
field and initialization left behind by removing the constructor argument.



##########
indexing-service/src/test/java/org/apache/druid/indexing/seekablestream/supervisor/SeekableStreamSupervisorStateTest.java:
##########
@@ -4275,43 +4275,62 @@ public void 
testDynamicAllocationScaleUpBlockedWhenCooldownNotElapsed()
   {
     final long scaleUpCooldown = Duration.standardHours(1).getMillis();
     final long unusedCooldown = 0L;
-    final StubServiceEmitter scalingEmitter = 
setupSupervisorForAutoScalingTest(scaleUpCooldown, unusedCooldown, 2);
+    setupSupervisorForAutoScalingTest(scaleUpCooldown, unusedCooldown, 2);
     final TestSeekableStreamSupervisor supervisor =
         new 
StateOverrideTestSeekableStreamSupervisor(SupervisorStateManager.BasicState.RUNNING);
 
     // First scale-up succeeds and stamps the last-scale timestamp.
-    supervisor.handleDynamicAllocationTasksNotice(() -> 5, () -> {}, 
scalingEmitter);
+    supervisor.handleDynamicAllocationTasksNotice(() -> 5, () -> {}, false);
     Assertions.assertEquals(5, supervisor.getIoConfig().getTaskCount());
 
     // Second scale-up is within the 1h minScaleUpDelay window and must be 
blocked.
-    supervisor.handleDynamicAllocationTasksNotice(() -> 7, () -> {}, 
scalingEmitter);
+    supervisor.handleDynamicAllocationTasksNotice(() -> 7, () -> {}, false);
     Assertions.assertEquals(5, supervisor.getIoConfig().getTaskCount(), 
"Second scale-up must not take effect");
 
     final List<ServiceMetricEvent> events =
-        
scalingEmitter.getMetricEvents(SeekableStreamSupervisor.AUTOSCALER_REQUIRED_TASKS_METRIC);
+        
emitter.getMetricEvents(SeekableStreamSupervisor.AUTOSCALER_REQUIRED_TASKS_METRIC);
     Assertions.assertEquals(2, events.size(), "Two required-tasks emissions 
expected (one applied, one skipped)");
     // First emission: the successful scale carries no skip-reason dim and 
reports the applied count.
     assertScaledToTaskCount(events.get(0), 5);
     // Second emission: the gated scale carries the cooldown skip-reason dim 
and the proposed (not applied) count.
     assertScaleSkipped(events.get(1), 7, "Scale cooldown not elapsed yet");
   }
 
+  @Test
+  public void 
test_dynamicAllocation_allowsScaleUpDuringRollover_evenIfCooldownNotElapsed()
+  {
+    final long scaleUpCooldown = Duration.standardHours(1).getMillis();
+    final long unusedCooldown = Duration.standardHours(1).getMillis();
+    setupSupervisorForAutoScalingTest(scaleUpCooldown, unusedCooldown, 2);
+    final TestSeekableStreamSupervisor supervisor =
+        new 
StateOverrideTestSeekableStreamSupervisor(SupervisorStateManager.BasicState.RUNNING);
+
+    supervisor.handleDynamicAllocationTasksNotice(() -> 5, () -> {}, true);

Review Comment:
   [P2] Exercise the rollover bypass with an active cooldown
   
   **Finding:** The new rollover tests call the notice only once, while 
dynamicTriggerLastScaleRunTime is still zero, so a one-hour cooldown has 
already elapsed and the scale-up test would pass even if the bypass were 
removed. The scale-down test has the same gap and passes false for 
isRolloverInProgress. The central cooldown-bypass behavior is therefore not 
protected by these tests.
   
   **Suggestion:** First perform a successful scale to stamp the cooldown, then 
invoke both rollover cases with isRolloverInProgress=true and assert that the 
second scale succeeds.



-- 
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]


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

Reply via email to