proc_cli/commands/
stuck.rs1use crate::core::{apply_filters, Process};
9use crate::error::Result;
10use crate::ui::{plural, Printer};
11use clap::Args;
12use dialoguer::Confirm;
13use std::time::Duration;
14
15#[derive(Args, Debug)]
17pub struct StuckCommand {
18 #[arg(long, short = 't', default_value = "300")]
20 pub timeout: u64,
21
22 #[arg(long, short = 'k')]
24 pub kill: bool,
25
26 #[arg(long)]
28 pub dry_run: bool,
29
30 #[arg(long, short = 'y')]
32 pub yes: bool,
33
34 #[arg(long, short = 'j')]
36 pub json: bool,
37
38 #[arg(long, short = 'v')]
40 pub verbose: bool,
41
42 #[arg(long = "in", short = 'i', num_args = 0..=1, default_missing_value = ".")]
44 pub in_dir: Option<String>,
45
46 #[arg(long = "by", short = 'b')]
48 pub by_name: Option<String>,
49}
50
51impl StuckCommand {
52 pub fn execute(&self) -> Result<()> {
54 let printer = Printer::from_flags(self.json, self.verbose);
55
56 let timeout = Duration::from_secs(self.timeout);
57 let mut processes = Process::find_stuck(timeout)?;
58
59 apply_filters(&mut processes, &self.in_dir, &self.by_name);
61
62 if processes.is_empty() {
63 printer.print_empty_result(
64 "stuck",
65 &format!("No stuck processes found (threshold: {}s)", self.timeout),
66 );
67 return Ok(());
68 }
69
70 printer.warning(&format!(
71 "Found {} potentially stuck process{}",
72 processes.len(),
73 plural(processes.len())
74 ));
75 printer.print_processes_as("stuck", &processes, None);
76
77 if self.kill && self.dry_run {
79 printer.print_processes(&processes);
80 printer.warning(&format!(
81 "Dry run: would kill {} stuck process{}",
82 processes.len(),
83 plural(processes.len())
84 ));
85 return Ok(());
86 }
87
88 if self.kill {
90 if !self.yes && !self.json {
91 let confirmed = Confirm::new()
92 .with_prompt(format!(
93 "Kill {} stuck process{}?",
94 processes.len(),
95 plural(processes.len())
96 ))
97 .default(false)
98 .interact()?;
99
100 if !confirmed {
101 printer.warning("Cancelled");
102 return Ok(());
103 }
104 }
105
106 let mut killed = Vec::new();
107 let mut failed = Vec::new();
108
109 for proc in processes {
110 match proc.kill_and_wait() {
112 Ok(_) => killed.push(proc),
113 Err(e) => failed.push((proc, e.to_string())),
114 }
115 }
116
117 printer.print_kill_result(&killed, &failed);
118 }
119
120 Ok(())
121 }
122}