1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
//! # Queueing Theory
//!
//! Queueing theory is the mathematical study of waiting lines, and much of
//! a delivery pipeline actually is a queue: a pull request waiting for a
//! reviewer, a commit waiting for a CI runner, a ticket waiting to be
//! picked up. Utilization — how busy a shared, capacity-constrained
//! resource is, as a proportion of its available capacity — is the key
//! quantity: wait time does not grow linearly with utilization, it grows
//! sharply as utilization approaches full capacity.
//!
//! ## Formula
//!
//! ```text
//! Utilization = arrival rate / service rate
//! Queue is stable when utilization < 1.0
//! ```
//!
//! ## Why it matters
//!
//! A resource running at 95% busy is often waiting many times longer than
//! one running at 80%, not just "a little worse" — wait time grows sharply,
//! not gradually, as utilization approaches capacity. A queue running at
//! 100% utilization on average has effectively infinite wait time in
//! practice, because real arrivals are uneven, not perfectly smooth. This
//! is why "our reviewers are almost always busy" is a warning sign about
//! wait times to come, not evidence of efficient resourcing, and why
//! deliberate headroom below full utilization is a design choice, not
//! waste.
//!
//! ## Example
//!
//! The topic doc's own worked example: a shared CI fleet found running
//! above 90% utilization during core hours — well past the point where
//! queueing theory predicts wait time grows sharply rather than gradually.
//! A queue with an arrival rate of 9 jobs/hour against a service rate of 10
//! jobs/hour runs at 90% utilization and is still stable; one with an
//! arrival rate of 11 jobs/hour against the same service rate is not.
//!
//! ```rust
//! use software_engineering::queueing_theory::{utilization, is_queue_stable};
//!
//! let near_capacity = utilization(9.0, 10.0).unwrap();
//! assert!((near_capacity - 0.9).abs() < 1e-9);
//! assert!(is_queue_stable(near_capacity));
//!
//! let overloaded = utilization(11.0, 10.0).unwrap();
//! assert!(!is_queue_stable(overloaded));
//! ```
//!
//! ## Pitfalls
//!
//! - **Sizing a shared resource's capacity to match its average arrival
//! rate exactly**: guarantees high utilization and runaway wait times
//! whenever demand is even briefly uneven. Plan deliberate headroom.
//! - **Reporting only mean wait time, never a percentile**: hides the long
//! tail that matters most to the people actually waiting in it.
//! - **Blending success, failure, and skip into one throughput number**:
//! a team under pressure can make throughput look healthy by quietly
//! letting the skip rate (abandoned or silently dropped work) rise. Track
//! arrival, success, failure, and skip rate as four separate numbers.
//! - **Treating "our people are always busy" as a compliment**: it is a
//! symptom of high utilization, the leading cause of long, unpredictable
//! wait times.
//!
//! ## Sources
//!
//! - Chapter 2.7, "Queueing theory."
//! - Little, John D. C. "A Proof for the Queuing Formula: L = λW." *Operations
//! Research*, 1961.
//!
//! Topic doc: software-engineering-metrics/locales/en-001/chapters/02-07-queueing-theory.md
/// Utilization: arrival rate divided by service rate for a shared,
/// capacity-constrained resource.
///
/// # Arguments
///
/// * `arrival_rate` — rate at which new work arrives at the resource.
/// * `service_rate` — rate at which the resource can process work.
///
/// # Returns
///
/// `Some(utilization)` as a fraction (e.g. `0.9` for 90% busy), or `None`
/// when `service_rate` is zero.
///
/// # Examples
///
/// ```rust
/// use software_engineering::queueing_theory::utilization;
///
/// let u = utilization(9.0, 10.0).unwrap();
/// assert!((u - 0.9).abs() < 1e-9);
/// assert_eq!(utilization(9.0, 0.0), None);
/// ```
/// Whether a queue is stable: utilization strictly less than 1.0.
///
/// A queue at or above 100% utilization has, in practice, unboundedly
/// growing wait time, because real arrivals are uneven rather than
/// perfectly smooth. Wait time grows sharply, not gradually, as utilization
/// approaches this threshold — treat utilization consistently near 1.0 as
/// an early warning, not just outright instability as the only concern.
///
/// # Arguments
///
/// * `utilization` — the resource's utilization as a fraction (see
/// [`utilization`]).
///
/// # Returns
///
/// `true` if `utilization < 1.0` (stable), `false` otherwise.
///
/// # Examples
///
/// ```rust
/// use software_engineering::queueing_theory::is_queue_stable;
///
/// assert!(is_queue_stable(0.9));
/// assert!(!is_queue_stable(1.0));
/// assert!(!is_queue_stable(1.1));
/// ```