deslicer_cli/commands/change/
status.rs1use clap::Args as ClapArgs;
2
3use crate::commands::pipeline::{authenticate, map_cli_error};
4use crate::observer_client::PlanProgress;
5use crate::output::emit_plan_progress;
6use crate::Ctx;
7
8#[derive(ClapArgs)]
9pub struct Args {
10 #[arg(long)]
11 pub plan_id: String,
12}
13
14const MAX_ATTEMPTS: u32 = 10;
15const INITIAL_DELAY_MS: u64 = 500;
16
17fn is_terminal_status(status: &str) -> bool {
18 matches!(
19 status,
20 "succeeded" | "failed" | "cancelled" | "completed" | "timed_out"
21 )
22}
23
24pub async fn run(ctx: Ctx, args: Args) -> i32 {
25 let (_session, client) = match authenticate(&ctx, None, Some(&args.plan_id)).await {
26 Ok(pair) => pair,
27 Err(err) => return map_cli_error(err),
28 };
29
30 let mut delay_ms = INITIAL_DELAY_MS;
31 let mut last: Option<PlanProgress> = None;
32
33 for attempt in 0..MAX_ATTEMPTS {
34 let progress = match client.progress(&args.plan_id).await {
35 Ok(progress) => progress,
36 Err(err) => return map_cli_error(err),
37 };
38
39 if is_terminal_status(&progress.status) {
40 return emit_plan_progress(&progress);
41 }
42
43 last = Some(progress);
44
45 if attempt + 1 < MAX_ATTEMPTS {
46 tokio::time::sleep(std::time::Duration::from_millis(delay_ms)).await;
47 delay_ms = delay_ms.saturating_mul(2);
48 }
49 }
50
51 match last {
52 Some(progress) => emit_plan_progress(&progress),
53 None => {
54 eprintln!("no progress available for plan {}", args.plan_id);
55 1
56 }
57 }
58}