cronoq_core/snapshot.rs
1//! Point-in-time metrics: pool state plus quality signals computed over a sliding window.
2
3use core::time::Duration;
4use std::sync::Arc;
5
6use crate::engine::Totals;
7use crate::spec::Priority;
8use crate::time::Time;
9
10/// State and windowed quality metrics of one pool.
11///
12/// Counters and ratios cover the last [`PoolSnapshot::window`]
13/// (`CoreConfig::metrics_window`); `worker_seconds` and `cost` accumulate since start.
14#[derive(Clone, Debug)]
15pub struct PoolSnapshot {
16 /// Pool name.
17 pub name: Arc<str>,
18 /// Workers currently available to the pool.
19 pub capacity: u32,
20 /// Workers currently running a task.
21 pub busy: u32,
22 /// Workers held free for upcoming fixed-start tasks.
23 pub held: u32,
24 /// Last autoscaler target (equals capacity without autoscaling).
25 pub desired: u32,
26 /// Tasks not yet running (blocked, scheduled, ready or retrying), by priority class.
27 pub pending_by_class: [usize; Priority::COUNT],
28 /// Tasks ready to run right now (queued or due).
29 pub ready: usize,
30 /// Active fixed-start reservations.
31 pub reservations: usize,
32 /// Length of the metrics window.
33 pub window: Duration,
34 /// Attempts started in the window.
35 pub dispatched: u64,
36 /// Tasks that succeeded in the window.
37 pub succeeded: u64,
38 /// Attempts that failed in the window (including ones that will be retried).
39 pub failed: u64,
40 /// Retries scheduled in the window.
41 pub retried: u64,
42 /// Fraction of dispatches where no strictly higher class was waiting in the pool.
43 pub priority_adherence: f64,
44 /// Fraction of fixed-start tasks started within tolerance (first attempts only).
45 pub fixed_start_hit_rate: f64,
46 /// Busy slot-seconds / capacity slot-seconds.
47 pub utilization: f64,
48 /// Completed work seconds / capacity slot-seconds.
49 pub schedule_efficiency: f64,
50 /// Mean time from submission to first start.
51 pub wait_mean: Duration,
52 /// Median time from submission to first start.
53 pub wait_p50: Duration,
54 /// 90th-percentile time from submission to first start.
55 pub wait_p90: Duration,
56 /// 99th-percentile time from submission to first start.
57 pub wait_p99: Duration,
58 /// Median runtime of successful attempts.
59 pub run_p50: Duration,
60 /// 99th-percentile runtime of successful attempts.
61 pub run_p99: Duration,
62 /// Capacity slot-seconds provisioned since start.
63 pub worker_seconds: f64,
64 /// `worker_seconds × AutoscaleConfig::cost_per_worker_second` since start.
65 pub cost: f64,
66 /// Worker groups by label set (the unlabeled group first).
67 pub groups: Vec<GroupSnapshot>,
68}
69
70impl PoolSnapshot {
71 /// Total tasks not yet running.
72 pub fn pending(&self) -> usize {
73 self.pending_by_class.iter().sum()
74 }
75}
76
77/// Engine-wide snapshot returned by [`Core::snapshot`](crate::Core::snapshot).
78#[derive(Clone, Debug)]
79pub struct Snapshot {
80 /// Engine time of the snapshot.
81 pub at: Time,
82 /// Per-pool state, in configuration order.
83 pub pools: Vec<PoolSnapshot>,
84 /// Tasks not yet in a terminal status.
85 pub live_tasks: usize,
86 /// Attempts currently running.
87 pub running: usize,
88 /// Tasks not yet running.
89 pub pending: usize,
90 /// Counters since start.
91 pub totals: Totals,
92}
93
94impl Snapshot {
95 /// The snapshot of the pool named `name`.
96 pub fn pool(&self, name: &str) -> Option<&PoolSnapshot> {
97 self.pools.iter().find(|p| &*p.name == name)
98 }
99}
100
101/// Capacity of the workers of a pool that share one label set.
102#[derive(Clone, Debug, Default, PartialEq)]
103pub struct GroupSnapshot {
104 /// The group's labels, sorted (empty for unlabeled workers).
105 pub labels: Vec<(Arc<str>, Arc<str>)>,
106 /// Slots of the group's workers.
107 pub capacity: u32,
108 /// Slots running a task.
109 pub busy: u32,
110}