mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-10-02 02:13:49 +00:00
190 lines
5.9 KiB
Rust
190 lines
5.9 KiB
Rust
use std::time::Duration;
|
|
|
|
use fabro_core::retry::{BackoffPolicy, RetryPolicy};
|
|
use fabro_graphviz::graph::types::{Graph as GvGraph, Node as GvNode};
|
|
|
|
const DEFAULT_BACKOFF: BackoffPolicy = BackoffPolicy {
|
|
initial_delay: Duration::from_secs(5),
|
|
factor: 2.0,
|
|
max_delay: Duration::from_mins(1),
|
|
jitter: true,
|
|
};
|
|
|
|
/// Build a retry policy from node and graph attributes.
|
|
/// If the node has a `retry_policy` attribute naming a preset, use that.
|
|
/// Otherwise, fall back to `max_retries` / graph default.
|
|
pub(crate) fn build_retry_policy(node: &GvNode, graph: &GvGraph) -> RetryPolicy {
|
|
if let Some(preset) = node.retry_policy() {
|
|
if let Some(policy) = preset_retry_policy(preset) {
|
|
return policy;
|
|
}
|
|
}
|
|
|
|
let max_retries = node
|
|
.max_retries()
|
|
.unwrap_or_else(|| graph.default_max_retries());
|
|
let max_attempts = u32::try_from(max_retries + 1).unwrap_or(1).max(1);
|
|
|
|
RetryPolicy {
|
|
max_attempts,
|
|
backoff: DEFAULT_BACKOFF,
|
|
}
|
|
}
|
|
|
|
fn preset_retry_policy(preset: &str) -> Option<RetryPolicy> {
|
|
match preset {
|
|
"none" => Some(RetryPolicy {
|
|
max_attempts: 1,
|
|
backoff: DEFAULT_BACKOFF,
|
|
}),
|
|
"standard" => Some(RetryPolicy {
|
|
max_attempts: 5,
|
|
backoff: DEFAULT_BACKOFF,
|
|
}),
|
|
"aggressive" => Some(RetryPolicy {
|
|
max_attempts: 5,
|
|
backoff: BackoffPolicy {
|
|
initial_delay: Duration::from_millis(500),
|
|
..DEFAULT_BACKOFF
|
|
},
|
|
}),
|
|
"linear" => Some(RetryPolicy {
|
|
max_attempts: 3,
|
|
backoff: BackoffPolicy {
|
|
initial_delay: Duration::from_millis(500),
|
|
factor: 1.0,
|
|
..DEFAULT_BACKOFF
|
|
},
|
|
}),
|
|
"patient" => Some(RetryPolicy {
|
|
max_attempts: 3,
|
|
backoff: BackoffPolicy {
|
|
initial_delay: Duration::from_secs(2),
|
|
factor: 3.0,
|
|
..DEFAULT_BACKOFF
|
|
},
|
|
}),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use std::time::Duration;
|
|
|
|
use fabro_graphviz::graph::{AttrValue, Graph, Node};
|
|
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn build_retry_policy_from_node() {
|
|
let mut node = Node::new("n");
|
|
node.attrs
|
|
.insert("max_retries".to_string(), AttrValue::Integer(3));
|
|
let graph = Graph::new("test");
|
|
let policy = build_retry_policy(&node, &graph);
|
|
assert_eq!(policy.max_attempts, 4);
|
|
}
|
|
|
|
#[test]
|
|
fn build_retry_policy_from_graph_default() {
|
|
let node = Node::new("n");
|
|
let mut graph = Graph::new("test");
|
|
graph
|
|
.attrs
|
|
.insert("default_max_retries".to_string(), AttrValue::Integer(2));
|
|
let policy = build_retry_policy(&node, &graph);
|
|
assert_eq!(policy.max_attempts, 3);
|
|
}
|
|
|
|
#[test]
|
|
fn build_retry_policy_no_attrs_uses_graph_default_0() {
|
|
let node = Node::new("n");
|
|
let graph = Graph::new("test");
|
|
let policy = build_retry_policy(&node, &graph);
|
|
assert_eq!(policy.max_attempts, 1);
|
|
}
|
|
|
|
#[test]
|
|
fn build_retry_policy_from_retry_policy_attr() {
|
|
let mut node = Node::new("n");
|
|
node.attrs.insert(
|
|
"retry_policy".to_string(),
|
|
AttrValue::String("aggressive".to_string()),
|
|
);
|
|
let graph = Graph::new("test");
|
|
let policy = build_retry_policy(&node, &graph);
|
|
assert_eq!(policy.max_attempts, 5);
|
|
assert_eq!(policy.backoff.initial_delay, Duration::from_millis(500));
|
|
}
|
|
|
|
#[test]
|
|
fn build_retry_policy_fallback_when_no_retry_policy_attr() {
|
|
let mut node = Node::new("n");
|
|
node.attrs
|
|
.insert("max_retries".to_string(), AttrValue::Integer(3));
|
|
let graph = Graph::new("test");
|
|
let policy = build_retry_policy(&node, &graph);
|
|
assert_eq!(policy.max_attempts, 4);
|
|
assert_eq!(policy.backoff.initial_delay, Duration::from_secs(5));
|
|
}
|
|
|
|
#[test]
|
|
fn build_retry_policy_all_presets() {
|
|
let presets = [
|
|
("none", 1u32),
|
|
("standard", 5),
|
|
("aggressive", 5),
|
|
("linear", 3),
|
|
("patient", 3),
|
|
];
|
|
let graph = Graph::new("test");
|
|
let (name, expected) = presets[0];
|
|
let mut node = Node::new("n");
|
|
node.attrs.insert(
|
|
"retry_policy".to_string(),
|
|
AttrValue::String(name.to_string()),
|
|
);
|
|
assert_eq!(build_retry_policy(&node, &graph).max_attempts, expected);
|
|
|
|
let (name, expected) = presets[1];
|
|
node.attrs.insert(
|
|
"retry_policy".to_string(),
|
|
AttrValue::String(name.to_string()),
|
|
);
|
|
assert_eq!(build_retry_policy(&node, &graph).max_attempts, expected);
|
|
|
|
let (name, expected) = presets[2];
|
|
node.attrs.insert(
|
|
"retry_policy".to_string(),
|
|
AttrValue::String(name.to_string()),
|
|
);
|
|
assert_eq!(build_retry_policy(&node, &graph).max_attempts, expected);
|
|
|
|
let (name, expected) = presets[3];
|
|
node.attrs.insert(
|
|
"retry_policy".to_string(),
|
|
AttrValue::String(name.to_string()),
|
|
);
|
|
assert_eq!(build_retry_policy(&node, &graph).max_attempts, expected);
|
|
|
|
let (name, expected) = presets[4];
|
|
node.attrs.insert(
|
|
"retry_policy".to_string(),
|
|
AttrValue::String(name.to_string()),
|
|
);
|
|
assert_eq!(build_retry_policy(&node, &graph).max_attempts, expected);
|
|
}
|
|
|
|
#[test]
|
|
fn build_retry_policy_unknown_preset_falls_back() {
|
|
let mut node = Node::new("n");
|
|
node.attrs.insert(
|
|
"retry_policy".to_string(),
|
|
AttrValue::String("unknown_preset".to_string()),
|
|
);
|
|
let graph = Graph::new("test");
|
|
let policy = build_retry_policy(&node, &graph);
|
|
assert_eq!(policy.max_attempts, 1);
|
|
}
|
|
}
|