Summary
In the DefaultScheduler path the idle-supervisor redistribute pass runs twice in a single scheduling round, so the per-topology nimbus.even.rebalance.max.free.per.topology cap is enforced twice — an under-assigned topology can relocate up to 2 × cap workers per round.
Introduced by #8778 (opt-in idle-supervisor rebalance). Off by default, so there is no impact unless nimbus.even.rebalance.idle.supervisor.enabled=true.
Mechanism
defaultSchedule calls redistributeOntoIdleSupervisors over the full topology set once (DefaultScheduler.java:75), then for each needs-scheduling topology calls EvenScheduler.scheduleTopologiesEvenly(new Topologies(topology), cluster) (DefaultScheduler.java:106) — and scheduleTopologiesEvenly calls redistributeOntoIdleSupervisors again on entry (EvenScheduler.java:336).
Eligibility (isIdleSupervisorAvailableForEvenRebalance) is getUsedPorts(...).isEmpty(). The first pass only marks the supervisors it actually filled; any supervisor still idle afterwards is re-selected in the second (per-topology) pass, applying the cap a second time.
Using EvenScheduler directly is unaffected (it runs scheduleTopologiesEvenly once over the full set). RAS is unaffected.
Reproduce
idle.supervisor.enabled=true, max.free.per.topology > 0
- 2+ fully idle supervisors
- an under-assigned topology whose donor supervisor still holds ≥2 of its workers
- DefaultScheduler (or IsolationScheduler leftover delegation)
Impact
Low: off by default; excess relocation churn (throttle exceeded), not a crash or loss, and it converges over rounds. Scoped to the DefaultScheduler / EvenScheduler path.
Suggested fix
Run the redistribute pass once per round — either guard re-entry in scheduleTopologiesEvenly, or keep the single full-set pass in DefaultScheduler and skip the redistribute in the per-topology delegation. Dropping the full-set call instead would break the round-robin fairness that lets multiple topologies share idle slots, so it should be kept.
Summary
In the
DefaultSchedulerpath the idle-supervisor redistribute pass runs twice in a single scheduling round, so the per-topologynimbus.even.rebalance.max.free.per.topologycap is enforced twice — an under-assigned topology can relocate up to2 × capworkers per round.Introduced by #8778 (opt-in idle-supervisor rebalance). Off by default, so there is no impact unless
nimbus.even.rebalance.idle.supervisor.enabled=true.Mechanism
defaultSchedulecallsredistributeOntoIdleSupervisorsover the full topology set once (DefaultScheduler.java:75), then for each needs-scheduling topology callsEvenScheduler.scheduleTopologiesEvenly(new Topologies(topology), cluster)(DefaultScheduler.java:106) — andscheduleTopologiesEvenlycallsredistributeOntoIdleSupervisorsagain on entry (EvenScheduler.java:336).Eligibility (
isIdleSupervisorAvailableForEvenRebalance) isgetUsedPorts(...).isEmpty(). The first pass only marks the supervisors it actually filled; any supervisor still idle afterwards is re-selected in the second (per-topology) pass, applying the cap a second time.Using
EvenSchedulerdirectly is unaffected (it runsscheduleTopologiesEvenlyonce over the full set). RAS is unaffected.Reproduce
idle.supervisor.enabled=true,max.free.per.topology> 0Impact
Low: off by default; excess relocation churn (throttle exceeded), not a crash or loss, and it converges over rounds. Scoped to the DefaultScheduler / EvenScheduler path.
Suggested fix
Run the redistribute pass once per round — either guard re-entry in
scheduleTopologiesEvenly, or keep the single full-set pass inDefaultSchedulerand skip the redistribute in the per-topology delegation. Dropping the full-set call instead would break the round-robin fairness that lets multiple topologies share idle slots, so it should be kept.