Anton Kalashnikov created FLINK-40379:
-----------------------------------------
Summary: AdaptiveScheduler is in restart loop when task
cancellation consistently times out
Key: FLINK-40379
URL: https://issues.apache.org/jira/browse/FLINK-40379
Project: Flink
Issue Type: Bug
Reporter: Anton Kalashnikov
When task cancellation keeps timing out during a scale-up, the affected TM is
killed, the cluster ends up with fewer slots than before, and the
AdaptiveScheduler loops forever in Restarting -> WaitingForResources ->
CreatingExecutionGraph -> Restarting, never making progress
*Root cause*
WaitingForResources, doesn't wait for resources long enough after the TM was
canceled(if TM is stuck in canceled, it will be terminated in a hard way and it
needs some time to restart it). So the stabilization timeout for after restart
is normally small to avoid downtime in normal cases, and "sufficient resources"
means slots >= lowerBound but lowerBound is hard-coded to 1, so the gate is
always open
*result:*
The scheduler immediately re-enters CreatingExecutionGraph -> Executing,
cancellation times out again, the TM is killed, and the loop continues with the
same or fewer slots
State transition entry point: Restarting.java:116 in confluentinc/flink
(onGloballyTerminalState handler)
*Fix proposal:*
Adding `AdaptiveScheduler#getFreeSlotsVertexParallelism()`, computed from free
slots only (`DeclarativeSlotPool#getFreeSlotTracker`), excluding slots still
reserved by the execution that is being canceled. WaitingForResources now uses
this (via a targetParallelism gate) to redefine "desired resources" only for
rescale-triggered restarts: desired means the free-slot-achievable parallelism
is at least what was free right before the restart. The onFailure (TM/slot
loss) and reconfigure paths are untouched: they never carry a restart target,
so they keep the original all-slots-based
hasSufficientResources()/hasDesiredResources() unchanged
Adding a new dedicated option
`jobmanager.adaptive-scheduler.rescale.resource-stabilization-timeout` (default
2 min), used only for rescale-triggered restarts. It bounds how long the
scheduler waits, after a rescale-restart, for free slots to reach the
pre-restart parallelism before falling back to running with whatever's
currently sufficient. Keeping it separate from the submission path means
initial job-submission latency is unaffected
*Behavior comparison:*
||Scenario||Resource situation||master||This branch (final)||Difference||
|Initial submission|Full desired reached in time|Don't wait as soon as
sufficient|Identical - this path never carries a restart target, code
untouched|None|
|Initial submission|Only sufficient (< desired) available|After sufficient
resources appear, waits 10s for desired, then runs with
sufficient|Identical|None|
|Scale up (RESCALE)|Free slots catch up to pre-restart target quickly|All-slots
check usually (incorrectly) reports "unchanged" right after cancel and jumps
straight to {{{}CreatingExecutionGraph{}}}, potentially racing on slots not yet
actually free|Free-slots check correctly detects the gap, enters
{{{}WaitingForResources{}}}, but exits the stabilizing phase almost as fast
once slots genuinely free up|Similar wall-clock time in the good case, but no
longer racing ahead of real slot availability|
|Scale up (RESCALE)|Sufficient but < pre-restart target for a while|No
dedicated wait tied to the rescale target: either proceeds near-immediately on
the (possibly wrong) all-slots view, or - if the mismatch is caught - waits
only 10s against the job's generic desired resources (not the specific
pre-restart target), then runs at whatever's sufficient|Waits up to 2 min
specifically for free slots to reach the pre-restart target before falling back
to "sufficient"|New code waits materially longer (2 min vs ~0-10s) for the
actual intended target before settling for less - fewer premature under-scaled
restarts, at the cost of up to ~2 min extra restart latency in the worst case|
|Scale down (RESCALE)|Same two sub-cases - identical code path,
direction-agnostic (only checks whether free slots reach what was achievable
pre-restart)|Same as scale-up row|Same as scale-up row|Same as scale-up row|
|TaskManager/slot failure (task exception restart)|Desired reached quickly /
only sufficient available|Restart target is {{null}} here in both versions -
untouched, uses 10s + all-slots desired/sufficient checks|Identical|None|
|Reconfigure (JAR/config change restart)|Desired reached quickly / only
sufficient available|Restart target is {{null}} here in both versions -
untouched|Identical|None|
--
This message was sent by Atlassian Jira
(v8.20.10#820010)