Fix scheduler readiness semantics#509
Conversation
There was a problem hiding this comment.
Code Review
This pull request implements the redesigned scheduler readiness and fulfillment semantics (RFE498), switching the default policy stack to priority + gang and reordering the cycle actions to Allocate → Dispatch → Shuffle. It replaces the modulo-based gang checks with absolute target calculations and defers idle executor accounting in DRF and Priority policies until dispatch binding. The review feedback suggests optimizing the plugin conjunction loops in PluginManager by short-circuiting on false opinions, and refactoring GangPlugin to extract the duplicated incomplete_tasks calculation into a helper function.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| let mut result = None; | ||
| for (_, plugin) in plugins.iter() { | ||
| if let Some(ready) = plugin.is_ready(ssn) { | ||
| result = Some(result.unwrap_or(true) && ready); | ||
| } | ||
| } |
There was a problem hiding this comment.
We can optimize the conjunction loop by short-circuiting and returning early if any plugin returns Some(false). Since the final result is an AND of all opinions, a single false opinion guarantees the final result will be false.
let mut result = None;
for (_, plugin) in plugins.iter() {
if let Some(ready) = plugin.is_ready(ssn) {
if !ready {
return Ok(false);
}
result = Some(true);
}
}| let mut result = None; | ||
| for (_, plugin) in plugins.iter() { | ||
| if let Some(fulfilled) = plugin.is_fulfilled(ssn) { | ||
| result = Some(result.unwrap_or(true) && fulfilled); | ||
| } | ||
| } |
There was a problem hiding this comment.
| let incomplete_tasks = [TaskState::Pending, TaskState::Running] | ||
| .iter() | ||
| .map(|task_state| { | ||
| ssn.tasks_status | ||
| .get(task_state) | ||
| .copied() | ||
| .unwrap_or(0) | ||
| .max(0) as u64 | ||
| }) | ||
| .sum::<u64>(); |
There was a problem hiding this comment.
The logic to calculate incomplete_tasks is duplicated between is_ready and is_fulfilled. We should extract this into a private helper function to improve maintainability and readability.
Here is an example of the helper function you can define in gang.rs:
fn get_incomplete_tasks(ssn: &SessionInfoPtr) -> u64 {
[TaskState::Pending, TaskState::Running]
.iter()
.map(|task_state| {
ssn.tasks_status
.get(task_state)
.copied()
.unwrap_or(0)
.max(0) as u64
})
.sum::<u64>()
} let incomplete_tasks = get_incomplete_tasks(ssn);| let incomplete_tasks = [TaskState::Pending, TaskState::Running] | ||
| .iter() | ||
| .map(|task_state| { | ||
| ssn.tasks_status | ||
| .get(task_state) | ||
| .copied() | ||
| .unwrap_or(0) | ||
| .max(0) as u64 | ||
| }) | ||
| .sum::<u64>(); |
Summary
Allocate -> Dispatch -> ShuffleorderContext::is_readyandContext::is_fulfilledboolean while allowing individual plugins to abstain withNonePluginManagerignore abstentions, combine concrete opinions, and returntruewhen every plugin abstainsBatchPlugin, load it implicitly like Shim, and omit it from configurable policy listsgangpolicy name is intentionally rejectedRoot cause
The reverted #500 implementation mixed allocation and dispatch readiness semantics and treated an all-abstaining plugin set as an optional scheduler result. That could leave a session stuck when its executor was already Binding. The revised design keeps optionality inside plugins only: allocation asks whether executor supply is fulfilled, dispatch asks whether ready/bound capacity exists, and Context always receives a boolean decision. If every plugin abstains, the action is considered satisfied. Batch is always loaded so valid Priority/DRF stacks have a concrete readiness owner without listing it in configuration.
Validation
cargo fmt --checkcargo test -p flame-session-manager -- --test-threads=1(304 passed)cargo test -p common ctx::(33 passed)cargo test -p flmadm(39 passed)cargo test -p flame-executor-manager shims:: -- --test-threads=4(14 passed)git diff --checkAddresses #498 and replaces the scheduler behavior reverted by #508.