Skip to main content

deepstrike_core/scheduler/
runnable.rs

1//! Deterministic merge point for every kind of local runnable work.
2
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
6#[serde(rename_all = "snake_case")]
7pub enum LocalRunnableKind {
8    WorkflowNode,
9    NestedTask,
10    TimerWaiter,
11    MessageWaiter,
12    EventWaiter,
13}
14
15#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
16pub struct LocalRunnable {
17    pub id: String,
18    pub kind: LocalRunnableKind,
19    /// Rank assigned by the source scheduler. Sources share one merge/tie-break path.
20    pub source_rank: u64,
21}
22
23impl LocalRunnable {
24    pub fn workflow(id: impl Into<String>, source_rank: u64) -> Self {
25        Self {
26            id: id.into(),
27            kind: LocalRunnableKind::WorkflowNode,
28            source_rank,
29        }
30    }
31}
32
33/// Stable total order: source preference first, canonical id second, kind last.
34pub fn order_runnables(mut candidates: Vec<LocalRunnable>) -> Vec<LocalRunnable> {
35    candidates.sort_by(|left, right| {
36        left.source_rank
37            .cmp(&right.source_rank)
38            .then_with(|| left.id.cmp(&right.id))
39            .then_with(|| left.kind.cmp(&right.kind))
40    });
41    candidates
42}