Retry loops need an explicit budget so failure remains bounded and inspectable.

Program

Play the program to choose a retry budget and watch the deterministic status list.

retry_budget_model.rs
fn main() {
    let max_attempts = ;
    let statuses = ["fail", "fail", "ok"];
    let result = first_success(&statuses, max_attempts);
    println!("{result}");
}

fn first_success(statuses: &[&str], max_attempts: usize) -> String {
    let mut attempts = 0;
    for status in statuses.iter().take(max_attempts) {
        attempts += 1;
        if *status == "ok" {
            return format!("success after {attempts}");
        }
    }
    format!("failed after {attempts}")
}
fn main() {
    let max_attempts = ;
    let statuses = ["fail", "fail", "ok"];
    let result = first_success(&statuses, max_attempts);
    println!("{result}");
}

fn first_success(statuses: &[&str], max_attempts: usize) -> String {
    let mut attempts = 0;
    for status in statuses.iter().take(max_attempts) {
        attempts += 1;
        if *status == "ok" {
            return format!("success after {attempts}");
        }
    }
    format!("failed after {attempts}")
}
fn main() {
    let max_attempts = ;
    let statuses = ["fail", "fail", "ok"];
    let result = first_success(&statuses, max_attempts);
    println!("{result}");
}

fn first_success(statuses: &[&str], max_attempts: usize) -> String {
    let mut attempts = 0;
    for status in statuses.iter().take(max_attempts) {
        attempts += 1;
        if *status == "ok" {
            return format!("success after {attempts}");
        }
    }
    format!("failed after {attempts}")
}
budget `take(max_attempts)` bounds the retry loop.
status list The statuses are fixed data so replay is deterministic.
outcome The returned message records whether success happened before the budget ended.