ralph/queue/
size_check.rs1use crate::constants::limits::{
12 DEFAULT_SIZE_WARNING_THRESHOLD_KB, DEFAULT_TASK_COUNT_WARNING_THRESHOLD,
13};
14use std::path::Path;
15
16use anyhow::{Context, Result};
17
18#[derive(Debug, Clone, Copy)]
20pub struct QueueSizeInfo {
21 pub file_size_kb: u64,
23 pub task_count: usize,
25}
26
27#[derive(Debug, Clone, Copy)]
29pub struct SizeCheckResult {
30 pub exceeds_size_threshold: bool,
32 pub exceeds_count_threshold: bool,
34 pub info: QueueSizeInfo,
36 pub size_threshold_kb: u32,
38 pub count_threshold: u32,
40}
41
42pub fn check_queue_size(
53 queue_path: &Path,
54 task_count: usize,
55 size_threshold_kb: u32,
56 count_threshold: u32,
57) -> Result<SizeCheckResult> {
58 let metadata = std::fs::metadata(queue_path)
59 .with_context(|| format!("read metadata for {}", queue_path.display()))?;
60
61 let file_size_bytes = metadata.len();
62 let file_size_kb = file_size_bytes / 1024;
63
64 let exceeds_size_threshold = file_size_kb > u64::from(size_threshold_kb);
65 let exceeds_count_threshold = task_count > count_threshold as usize;
66
67 Ok(SizeCheckResult {
68 exceeds_size_threshold,
69 exceeds_count_threshold,
70 info: QueueSizeInfo {
71 file_size_kb,
72 task_count,
73 },
74 size_threshold_kb,
75 count_threshold,
76 })
77}
78
79pub fn print_size_warning_if_needed(result: &SizeCheckResult, quiet: bool) {
85 if quiet {
86 return;
87 }
88
89 if !result.exceeds_size_threshold && !result.exceeds_count_threshold {
90 return;
91 }
92
93 eprintln!();
94 eprintln!("⚠️ Queue size warning:");
95
96 if result.exceeds_size_threshold {
97 eprintln!(
98 " Queue file size is {}KB (threshold: {}KB)",
99 result.info.file_size_kb, result.size_threshold_kb
100 );
101 }
102
103 if result.exceeds_count_threshold {
104 eprintln!(
105 " Queue has {} tasks (threshold: {})",
106 result.info.task_count, result.count_threshold
107 );
108 }
109
110 eprintln!();
111 eprintln!(" Consider running maintenance commands:");
112 eprintln!(" ralph queue archive # Move completed tasks to the done archive");
113 eprintln!(" ralph queue prune # Remove old tasks from the done archive");
114 eprintln!();
115}
116
117pub fn size_threshold_or_default(threshold: Option<u32>) -> u32 {
119 threshold.unwrap_or(DEFAULT_SIZE_WARNING_THRESHOLD_KB)
120}
121
122pub fn count_threshold_or_default(threshold: Option<u32>) -> u32 {
124 threshold.unwrap_or(DEFAULT_TASK_COUNT_WARNING_THRESHOLD)
125}
126
127#[cfg(test)]
128mod tests {
129 use super::*;
130 use tempfile::TempDir;
131
132 #[test]
133 fn check_queue_size_detects_size_threshold() -> Result<()> {
134 let temp = TempDir::new()?;
135 let queue_path = temp.path().join("queue.json");
136
137 let content = "x".repeat(1024);
139 std::fs::write(&queue_path, content)?;
140
141 let result = check_queue_size(&queue_path, 10, 0, 100)?;
143 assert!(result.exceeds_size_threshold);
144 assert!(!result.exceeds_count_threshold);
145 assert_eq!(result.info.file_size_kb, 1);
146
147 Ok(())
148 }
149
150 #[test]
151 fn check_queue_size_detects_count_threshold() -> Result<()> {
152 let temp = TempDir::new()?;
153 let queue_path = temp.path().join("queue.json");
154
155 std::fs::write(&queue_path, r#"{"tasks": []}"#)?;
157
158 let result = check_queue_size(&queue_path, 15, 1000, 10)?;
160 assert!(!result.exceeds_size_threshold);
161 assert!(result.exceeds_count_threshold);
162 assert_eq!(result.info.task_count, 15);
163
164 Ok(())
165 }
166
167 #[test]
168 fn check_queue_size_no_threshold_exceeded() -> Result<()> {
169 let temp = TempDir::new()?;
170 let queue_path = temp.path().join("queue.json");
171
172 std::fs::write(&queue_path, r#"{"tasks": []}"#)?;
174
175 let result = check_queue_size(&queue_path, 10, 10000, 5000)?;
177 assert!(!result.exceeds_size_threshold);
178 assert!(!result.exceeds_count_threshold);
179
180 Ok(())
181 }
182
183 #[test]
184 fn check_queue_size_detects_both_thresholds() -> Result<()> {
185 let temp = TempDir::new()?;
186 let queue_path = temp.path().join("queue.json");
187
188 let content = "x".repeat(2048);
190 std::fs::write(&queue_path, content)?;
191
192 let result = check_queue_size(&queue_path, 1000, 1, 500)?;
194 assert!(result.exceeds_size_threshold);
195 assert!(result.exceeds_count_threshold);
196
197 Ok(())
198 }
199
200 #[test]
201 fn threshold_helpers_return_defaults() {
202 assert_eq!(
203 size_threshold_or_default(None),
204 DEFAULT_SIZE_WARNING_THRESHOLD_KB
205 );
206 assert_eq!(
207 count_threshold_or_default(None),
208 DEFAULT_TASK_COUNT_WARNING_THRESHOLD
209 );
210 }
211
212 #[test]
213 fn threshold_helpers_return_configured() {
214 assert_eq!(size_threshold_or_default(Some(1000)), 1000);
215 assert_eq!(count_threshold_or_default(Some(1000)), 1000);
216 }
217}