Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/euclid/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ pub enum RoutingType {
Priority,
VolumeSplit,
VolumeSplitPriority,
DefaultFallback,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
Expand All @@ -164,6 +165,7 @@ pub enum Output {
Priority(Vec<ConnectorInfo>),
VolumeSplit(Vec<VolumeSplit<ConnectorInfo>>),
VolumeSplitPriority(Vec<VolumeSplit<Vec<ConnectorInfo>>>),
DefaultFallback(Vec<ConnectorInfo>),
}

#[derive(Clone, Debug, Default, Serialize, Deserialize)]
Expand Down
31 changes: 28 additions & 3 deletions src/euclid/handlers/routing_rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,7 @@ pub async fn routing_evaluate(
StaticRoutingAlgorithm::Single(conn.clone()).to_string()
))
}) {
Ok((_, eval)) => (out_enum, eval, Some("straight_through_rule".into())),
Ok((_, eval)) => (out_enum, eval, Some("straight_through".into())),
Err(e) => {
API_REQUEST_COUNTER
.with_label_values(&["routing_evaluate", "failure"])
Expand All @@ -537,7 +537,7 @@ pub async fn routing_evaluate(
StaticRoutingAlgorithm::Priority(connectors.clone()).to_string()
))
}) {
Ok((_, eval)) => (out_enum, eval, Some("priority_rule".into())),
Ok((_, eval)) => (out_enum, eval, Some("priority".into())),
Err(e) => {
API_REQUEST_COUNTER
.with_label_values(&["routing_evaluate", "failure"])
Expand All @@ -556,7 +556,7 @@ pub async fn routing_evaluate(
StaticRoutingAlgorithm::VolumeSplit(splits.clone()).to_string()
))
}) {
Ok((_, eval)) => (out_enum, eval, Some("volume_split_rule".into())),
Ok((_, eval)) => (out_enum, eval, Some("volume_split".into())),
Err(e) => {
API_REQUEST_COUNTER
.with_label_values(&["routing_evaluate", "failure"])
Expand Down Expand Up @@ -584,6 +584,25 @@ pub async fn routing_evaluate(
}
}
}

StaticRoutingAlgorithm::DefaultFallback(connectors) => {
let out_enum = Output::DefaultFallback(connectors.clone());
match evaluate_output(&out_enum).map_err(|_| {
EuclidErrors::FailedToEvaluateOutput(format!(
"{}",
StaticRoutingAlgorithm::DefaultFallback(connectors.clone()).to_string()
))
}) {
Ok((_, eval)) => (out_enum, eval, Some("default_fallback".into())),
Err(e) => {
API_REQUEST_COUNTER
.with_label_values(&["routing_evaluate", "failure"])
.inc();
timer.observe_duration();
return Err(e.into());
}
}
}
};

let eligible_connectors = if let Some(ref cfg) = state.config.routing_config {
Expand Down Expand Up @@ -626,6 +645,12 @@ fn format_output(output: &Output) -> Value {
"connectors": connectors
})
}
Output::DefaultFallback(connectors) => {
json!({
"type": "default_fallback",
"connectors": connectors
})
}
Output::VolumeSplit(splits) => {
let formatted_splits: Vec<Value> = splits
.iter()
Expand Down
1 change: 1 addition & 0 deletions src/euclid/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ pub fn evaluate_output(output: &Output) -> RoutingResult<(Vec<ConnectorInfo>, Ve
vec![first_connector.unwrap_or_default()],
))
}
Output::DefaultFallback(connectors) => Ok((connectors.clone(), connectors.to_vec())),
Copy link

Copilot AI Jul 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cloning the connectors vector twice causes two allocations. You can clone once and reuse the result, e.g. let cloned = connectors.clone(); Ok((cloned.clone(), cloned)) to reduce overhead.

Suggested change
Output::DefaultFallback(connectors) => Ok((connectors.clone(), connectors.to_vec())),
Output::DefaultFallback(connectors) => {
let cloned = connectors.clone();
Ok((cloned.clone(), cloned))
},

Copilot uses AI. Check for mistakes.
Output::VolumeSplit(splits) => {
let selected_connector = perform_volume_split(splits.clone())?;
Ok((vec![selected_connector.clone()], vec![selected_connector]))
Expand Down
1 change: 1 addition & 0 deletions src/euclid/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ pub enum StaticRoutingAlgorithm {
Priority(Vec<ConnectorInfo>),
VolumeSplit(Vec<super::ast::VolumeSplit<ConnectorInfo>>),
Advanced(Program),
DefaultFallback(Vec<ConnectorInfo>),
}

#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize, strum::Display)]
Expand Down
1 change: 1 addition & 0 deletions src/euclid/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ pub fn validate_routing_rule(
match &rule.algorithm {
StaticRoutingAlgorithm::Single(_)
| StaticRoutingAlgorithm::Priority(_)
| StaticRoutingAlgorithm::DefaultFallback(_)
Copy link

Copilot AI Jul 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The DefaultFallback variant is always considered valid, even if its connector list is empty. Consider adding a check to ensure the fallback list is non-empty to prevent downstream runtime errors.

Suggested change
| StaticRoutingAlgorithm::DefaultFallback(_)
| StaticRoutingAlgorithm::DefaultFallback(connectors) => {
if connectors.is_empty() {
return Err(EuclidErrors::InvalidRequest(
"DefaultFallback connector list cannot be empty".to_string(),
)
.into());
}
Ok(())
}

Copilot uses AI. Check for mistakes.
| StaticRoutingAlgorithm::VolumeSplit(_) => return Ok(()),
StaticRoutingAlgorithm::Advanced(program) => {
let mut errors = Vec::new();
Expand Down
Loading