hellodml commented on issue #18570:
URL: 
https://github.com/apache/dolphinscheduler/issues/18570#issuecomment-5352934150

   > We should use `ExceptionUtils.throwableOfType(...)` to judge if the 
exception is `CommandDuplicateHandleException` in 
`CommandEngine.bootstrapError`.
   
   Thanks for the careful review — you are right, and my original framing of the
   root cause was wrong. Here is a correction plus the evidence you asked for.
   
   ## 1. Correction: slot = -1 is NOT the blocker
   
   I re-examined the logs from the 100-minute outage (2026-08-19 09:40–11:20,
   container TZ Asia/Jakarta). Counting per hour:
   
   | hour | `slot (-1` | `Do rebalance failed` | `CommandEngine:[128]` overload 
|
   
|------|-----------:|----------------------:|-------------------------------:|
   | 09   | 39         | 56                    | 4325                           
|
   | 10   | **0**      | 120                   | **10791**                      
|
   | 11   | 20         | 92                    | 7471                           
|
   
   During hour 10 — the worst hour, zero commands consumed — `slot (-1` does not
   appear **even once**. So slot invalidation is incidental noise, not the 
cause.
   The actual blocker is exactly the path you described:
   
   ```
   INFO  [MasterCommandLoopThread] MasterServerLoadProtection:[56] -
     OverLoad: the workflow instance count: 25 exceeds the 
maxConcurrentWorkflowInstances
   WARN  [MasterCommandLoopThread] CommandEngine:[128] -
     The current server is overload, cannot consumes commands.
   ```
   (3597 occurrences of the WARN in hour 10 alone)
   
   Please disregard the "self-starvation via slot rebalance" theory in the issue
   body. I also accept your objection to my suggested fix #2 — preserving a 
stale
   slot would indeed create overlapping assignments in a multi-master 
deployment.
   
   @zhang-arvin — this also means #18572 would not have fixed the incident, and 
I
   am sorry for sending you down that path with a wrong issue description. That 
PR
   keeps the slot when the master is BUSY, but during the worst hour of our 
outage
   `slot (-1` never appears in the logs at all, while
   `CommandEngine:[128] "The current server is overload, cannot consumes 
commands"`
   appears 3597 times. Command consumption is gated by the overload check 
*before*
   the slot is ever used, so preserving the slot would not have let the master
   resume. Thanks for the quick turnaround regardless.
   
   ## 2. The missing link: why the count never drops
   
   Your model says the master recovers once the active workflow count falls 
below
   the threshold. That is correct in principle. In our incident **the count 
never
   moved**. Extracting every logged count value:
   
   ```
   hour 09:  21 ×36,  22 ×8,  23 ×22,  24 ×30,  25 ×2665
   hour 10:  25 ×7194          <- nothing but 25, for the whole hour
   hour 11:  22 ×5,  24 ×1,  25 ×2236,  26 ×3,  29 ×7
   ```
   
   Pinned at exactly 25 (limit was 20 at the time). 25 `WorkflowExecuteRunnable`
   instances were registered and none of them ever completed.
   
   What those wedged runnables look like in the metadata DB — of the 573 
workflow
   instances created during the outage window:
   
   ```
   instances with any task ever dispatched (host IS NOT NULL) :   0
   instances with tasks created but never dispatched          :  20
   instances with NO task instance rows at all                : 553
   ```
   
   So the runnables were stuck **before task creation**, not waiting on workers.
   Recovery required a container restart; the overload state never cleared on 
its own.
   
   ## 3. Evidence you requested
   
   ### Full exception chain (verbatim)
   
   ```
   java.util.concurrent.CompletionException: 
org.apache.dolphinscheduler.server.master.engine.exceptions.CommandDuplicateHandleException:
 The command: 520266 has already been handled
        at 
java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:273)
        at 
java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:280)
        at 
java.util.concurrent.CompletableFuture.uniApply(CompletableFuture.java:618)
        at 
java.util.concurrent.CompletableFuture$UniApply.tryFire(CompletableFuture.java:591)
        at 
java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:488)
        at 
java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1609)
        at 
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at 
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
   Caused by: 
org.apache.dolphinscheduler.server.master.engine.exceptions.CommandDuplicateHandleException:
 The command: 520266 has already been handled
        at 
org.apache.dolphinscheduler.server.master.engine.workflow.execution.WorkflowExecutionFactory.deleteCommandOrThrow(WorkflowExecutionFactory.java:76)
        at 
org.apache.dolphinscheduler.server.master.engine.workflow.execution.WorkflowExecutionFactory.createWorkflowExecuteRunnable(WorkflowExecutionFactory.java:51)
        at 
org.apache.dolphinscheduler.server.master.engine.workflow.execution.WorkflowExecutionFactory$$FastClassBySpringCGLIB$$46c24446.invoke(<generated>)
        at 
org.apache.dolphinscheduler.server.master.engine.workflow.execution.WorkflowExecutionFactory$$EnhancerBySpringCGLIB$$7ee93ae2.createWorkflowExecuteRunnable(<generated>)
   ```
   
   **This confirms your hypothesis exactly** — it arrives at `bootstrapError`
   wrapped in `CompletionException`, so a direct `instanceof` check cannot see 
it.
   `ExceptionUtils.throwableOfType(...)` is the right fix.
   
   ### Repeated command IDs
   
   ```
   2026-08-19 00:15   command 518447   workflow instance 515163
   2026-08-19 02:50   command 519296   workflow instance 516012
   2026-08-19 02:50   command 519297   workflow instance 516013
   2026-08-19 05:40   command 520266   workflow instance 516982
   2026-08-19 05:40   command 520267   workflow instance 516983
   ```
   
   Millisecond timeline for command 520266:
   
   ```
   05:40:01.071 INFO  CommandEngine:[190] - Success bootstrap command { "id" : 
520266, ... }
   05:40:01.082 WARN  CommandEngine:[204] - Failed bootstrap command  { "id" : 
520266, ... }
   05:40:01.085 INFO  CommandEngine:[211] - Set workflow instance 516982 state 
to FAILURE
   05:40:01.089 INFO  CommandEngine:[214] - Move command 520266 to error 
command table
   05:40:01.131 INFO  AbstractWorkflowLifecycleEventHandler:[47] - Begin fire 
workflow ...
   05:40:01.136 INFO  TaskGroupCoordinator:[365] - Success insert 
TaskGroupQueue: taskId=539177
   05:40:01.139 INFO  AbstractTaskStateAction:[272] - using taskGroup, success 
acquire taskGroup slot
           <-- 12 log lines total for this instance; nothing further ever 
happens
   ```
   
   Note lines 5–7 execute **after** the instance was set to FAILURE — the first
   (successful) execution's event bus keeps running and even acquires a task 
group
   slot, while the task itself is never dispatched.
   
   Downstream consequence in the same hour:
   
   ```
   java.lang.UnsupportedOperationException: The WorkflowInstance: 516982 state 
is FAILURE, no need to notify
   ```
   
   ### Master addresses
   
   Single master, standalone Docker, no multi-master:
   
   ```
   /nodes/master/172.18.0.2:5678
   /nodes/master-coordinator
   ```
   
   All workflow instances in the affected period carry `host = 172.18.0.2:5678`.
   So this reproduces with **one** master — no slot contention between peers 
involved.
   
   ## 4. Frequency, and why these instances are never reclaimed
   
   Measured over 11 hours on a steady workload (~340 `Success bootstrap` per 
hour):
   
   | hour | Success bootstrap | Failed bootstrap |
   |------|------------------:|-----------------:|
   | 00 | 337 | 1 |
   | 01 | 337 | 0 |
   | 02 | 338 | 2 |
   | 03 | 339 | 0 |
   | 04 | 342 | 0 |
   | 05 | 344 | 2 |
   | 06 | 341 | 0 |
   | 07 | 351 | 0 |
   | 08 | 341 | 0 |
   | 13 | 397 | 0 |
   
   Roughly 0.2% of SCHEDULER commands, always in the same minute as a cron 
batch.
   
   The stranded task instances are **never reclaimed**. Our DataX tasks use
   `timeout_notify_strategy = 0` (WARN only), so DS emits a "Task Timeout Warn"
   alert at the timeout and then leaves the task in `state=0` indefinitely. We 
have
   observed one sitting at `state=0` for over 23 hours. A reliable fingerprint 
for
   finding them in the metadata DB:
   
   ```sql
   SELECT * FROM t_ds_task_instance
   WHERE state = 6 AND host IS NULL AND log_path IS NULL
     AND TIMESTAMPDIFF(SECOND, start_time, end_time) = <task timeout in 
seconds>;
   ```
   
   ## 5. A second, easier-to-reproduce trigger for the same class of bug
   
   Running **individual tasks** (`command_type = 12`, EXECUTE_TASK) in quick
   succession against the same already-finished workflow instance hits the 
adjacent
   registration guard:
   
   ```
   java.lang.IllegalStateException: WorkflowExecuteRunnable(514408/<name>) 
already registered at WorkflowEventBusFireWorker
        at 
com.google.common.base.Preconditions.checkState(Preconditions.java:821)
        at 
org.apache.dolphinscheduler.server.master.engine.WorkflowEventBusFireWorker.registerWorkflowEventBus(WorkflowEventBusFireWorker.java:66)
        at 
org.apache.dolphinscheduler.server.master.engine.WorkflowEventBusCoordinator.registerWorkflowEventBus(WorkflowEventBusCoordinator.java:50)
        at 
org.apache.dolphinscheduler.server.master.engine.command.CommandEngine.bootstrapWorkflowExecution(CommandEngine.java:183)
   ```
   
   Steps:
   1. take any finished workflow instance with several serial tasks
   2. in the UI, run a single task from it; wait for it to finish
   3. run the next task ~3 minutes later
   4. repeat — the third or fourth throws the above, and its task stays 
`state=0` forever
   
   Both paths fail inside `CommandEngine.bootstrapWorkflowExecution` and both 
leave
   a task (and its task group slot) stranded. If the 
`ExceptionUtils.throwableOfType`
   fix also covers the `IllegalStateException: already registered` case, it may
   resolve both.
   
   Happy to run any additional diagnostics on this instance — it reproduces the
   0.2% case several times a day.


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