use metrics::{counter, describe_counter, describe_gauge, describe_histogram, gauge, histogram};
pub fn describe() {
describe_counter!(
"faucet_resilience_retries_total",
"Retry attempts, by op (sink_write|flush|state_put|source) and error class."
);
describe_histogram!(
"faucet_resilience_retry_sleep_seconds",
"Backoff sleep duration before a retry attempt, by op."
);
describe_counter!(
"faucet_resilience_giveup_total",
"Operations that exhausted their retry budget and failed, by op."
);
describe_gauge!(
"faucet_resilience_circuit_state",
"Circuit breaker state (0 closed, 1 open)."
);
describe_counter!(
"faucet_resilience_circuit_opened_total",
"Circuit breaker open events."
);
describe_counter!(
"faucet_resilience_poison_rows_total",
"Poison-pill rows resolved by terminal action (dlq|drop|fail)."
);
}
pub fn retry(pipeline: &str, row: &str, op: &'static str, class: &'static str) {
counter!(
"faucet_resilience_retries_total",
"pipeline" => pipeline.to_string(),
"row" => row.to_string(),
"op" => op,
"class" => class,
)
.increment(1);
}
pub fn retry_sleep(pipeline: &str, row: &str, op: &'static str, seconds: f64) {
histogram!(
"faucet_resilience_retry_sleep_seconds",
"pipeline" => pipeline.to_string(),
"row" => row.to_string(),
"op" => op,
)
.record(seconds);
}
pub fn giveup(pipeline: &str, row: &str, op: &'static str) {
counter!(
"faucet_resilience_giveup_total",
"pipeline" => pipeline.to_string(),
"row" => row.to_string(),
"op" => op,
)
.increment(1);
}
pub fn circuit_opened(pipeline: &str, row: &str) {
counter!(
"faucet_resilience_circuit_opened_total",
"pipeline" => pipeline.to_string(),
"row" => row.to_string(),
)
.increment(1);
gauge!(
"faucet_resilience_circuit_state",
"pipeline" => pipeline.to_string(),
"row" => row.to_string(),
)
.set(1.0);
}
pub fn poison_rows(pipeline: &str, row: &str, action: &'static str, n: u64) {
if n == 0 {
return;
}
counter!(
"faucet_resilience_poison_rows_total",
"pipeline" => pipeline.to_string(),
"row" => row.to_string(),
"action" => action,
)
.increment(n);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn describe_is_callable_and_idempotent() {
describe();
describe();
}
#[test]
fn emit_helpers_do_not_panic_without_recorder() {
retry("p", "r", "sink_write", "http_5xx");
retry_sleep("p", "r", "flush", 0.25);
giveup("p", "r", "state_put");
circuit_opened("p", "r");
poison_rows("p", "r", "dlq", 3);
poison_rows("p", "r", "drop", 0);
}
}