Skip to main content

deslicer_cli/commands/change/
status.rs

1use 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}