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


##########
indexing-service/src/main/java/org/apache/druid/indexing/seekablestream/supervisor/SeekableStreamSupervisor.java:
##########
@@ -2060,13 +2060,25 @@ public void runInternal()
       logDebugReport();
     }
     catch (Exception e) {
-      stateManager.recordThrowableEvent(e);
-      if (e instanceof StreamException) {
-        // When a StreamException is thrown, the error message is more useful 
than the stack trace in telling what's wrong.
-        log.makeAlert("Exception in supervisor run loop for supervisor[%s] for 
dataSource[%s]: [%s]",
-            supervisorId, dataSource, e.getMessage()).emit();
+      if (e instanceof ExecutionException || e instanceof 
InterruptedException) {

Review Comment:
   [P1] Classify task failures where they are recorded
   
   **Finding:** Recoverable pause/checkpoint RPC failures do not reach this 
catch as ExecutionException. FutureUtils.coalesce converts failed task futures 
into Either.error; checkpointTaskGroup records pauseException directly, and 
verifyAndMergeCheckpoints similarly records checkpoint errors. markRunFinished 
therefore still counts these runs as failed, so repeated recoverable task 
communication failures can still trigger UNHEALTHY_SUPERVISOR despite this 
change.
   
   **Suggestion:** Apply the recoverable-error policy at the task callback 
recording sites, with regression coverage for failed pause and checkpoint 
futures.



##########
processing/src/test/java/org/apache/druid/segment/join/PostJoinCursorTest.java:
##########
@@ -237,7 +237,7 @@ private void testAdvance(boolean withInterruption) throws 
IOException, Interrupt
     joinCursorThread.setUncaughtExceptionHandler(exceptionHandler);
     joinCursorThread.start();
 
-    countDownLatch.await(1, TimeUnit.SECONDS);
+    assertTrue(countDownLatch.await(1, TimeUnit.SECONDS));

Review Comment:
   [P1] Interrupt the infinite cursor thread on assertion failure
   
   **Finding:** If a slow or loaded test runner causes await to time out, the 
new assertion throws before joinCursorThread.interrupt(). The worker is a 
non-daemon thread whose CursorNoAdvance reports isDone() as false and whose 
value matcher always rejects rows, so it can continue spinning indefinitely and 
prevent the test JVM from exiting. The previous timeout path still reached the 
interrupt.
   
   **Suggestion:** Put interruption and bounded thread cleanup in a finally 
block so the worker is stopped even when the latch assertion fails.



##########
indexing-service/src/main/java/org/apache/druid/indexing/seekablestream/supervisor/SeekableStreamSupervisor.java:
##########
@@ -2060,13 +2060,25 @@ public void runInternal()
       logDebugReport();
     }
     catch (Exception e) {
-      stateManager.recordThrowableEvent(e);
-      if (e instanceof StreamException) {
-        // When a StreamException is thrown, the error message is more useful 
than the stack trace in telling what's wrong.
-        log.makeAlert("Exception in supervisor run loop for supervisor[%s] for 
dataSource[%s]: [%s]",
-            supervisorId, dataSource, e.getMessage()).emit();
+      if (e instanceof ExecutionException || e instanceof 
InterruptedException) {
+        // Task-level errors (e.g., task communication timeouts) are 
recoverable and should not
+        // cause the supervisor to enter UNHEALTHY state. Log a warning 
instead of recording
+        // as a throwable event that would count toward the unhealthiness 
threshold.
+        log.noStackTrace().warn(
+            e,

Review Comment:
   [P2] Avoid counting an aborted iteration as a successful run
   
   **Finding:** When an ExecutionException or InterruptedException aborts the 
first iteration before task discovery/checkpointing completes, this branch 
leaves currentRunSuccessful true. The unconditional finally call to 
markRunFinished then sets atLeastOneSuccessfulRun, increments the 
successful-run counter, and transitions to RUNNING. Subsequent stream 
connection failures bypass the first-run early-return guard, and an 
already-unhealthy supervisor can also be declared recovered after enough 
aborted iterations.
   
   **Suggestion:** Represent recoverable aborted iterations separately from 
successful and unhealthy failures, preserving first-run and recovery 
bookkeeping until an iteration completes.



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