Skip to content

Commit

Permalink
feat(euclid): add dynamic routing in core flows (#6333)
Browse files Browse the repository at this point in the history
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
  • Loading branch information
prajjwalkumar17 and hyperswitch-bot[bot] authored Oct 25, 2024
1 parent 90765be commit ce732db
Show file tree
Hide file tree
Showing 11 changed files with 605 additions and 492 deletions.
184 changes: 10 additions & 174 deletions api-reference/openapi_spec.json
Original file line number Diff line number Diff line change
Expand Up @@ -3952,12 +3952,12 @@
}
},
{
"name": "status",
"name": "enable",
"in": "query",
"description": "Boolean value for mentioning the expected state of dynamic routing",
"description": "Feature to enable for success based routing",
"required": true,
"schema": {
"type": "boolean"
"$ref": "#/components/schemas/SuccessBasedRoutingFeatures"
}
}
],
Expand Down Expand Up @@ -3998,87 +3998,6 @@
]
}
},
"/account/:account_id/business_profile/:profile_id/dynamic_routing/success_based/config/:algorithm_id": {
"patch": {
"tags": [
"Routing"
],
"summary": "Routing - Update config for success based dynamic routing",
"description": "Update config for success based dynamic routing",
"operationId": "Update configs for success based dynamic routing algorithm",
"parameters": [
{
"name": "account_id",
"in": "path",
"description": "Merchant id",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "profile_id",
"in": "path",
"description": "The unique identifier for a profile",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "algorithm_id",
"in": "path",
"description": "The unique identifier for routing algorithm",
"required": true,
"schema": {
"type": "string"
}
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SuccessBasedRoutingConfig"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Routing Algorithm updated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/RoutingDictionaryRecord"
}
}
}
},
"400": {
"description": "Request body is malformed"
},
"403": {
"description": "Forbidden"
},
"404": {
"description": "Resource missing"
},
"422": {
"description": "Unprocessable request"
},
"500": {
"description": "Internal server error"
}
},
"security": [
{
"admin_api_key": []
}
]
}
},
"/blocklist": {
"delete": {
"tags": [
Expand Down Expand Up @@ -9458,23 +9377,6 @@
"ZWL"
]
},
"CurrentBlockThreshold": {
"type": "object",
"properties": {
"duration_in_mins": {
"type": "integer",
"format": "int64",
"nullable": true,
"minimum": 0
},
"max_total_count": {
"type": "integer",
"format": "int64",
"nullable": true,
"minimum": 0
}
}
},
"CustomerAcceptance": {
"type": "object",
"description": "This \"CustomerAcceptance\" object is passed during Payments-Confirm request, it enlists the type, time, and mode of acceptance properties related to an acceptance done by the customer. The customer_acceptance sub object is usually passed by the SDK or client.",
Expand Down Expand Up @@ -23624,80 +23526,14 @@
"destination"
]
},
"SuccessBasedRoutingConfig": {
"type": "object",
"properties": {
"params": {
"type": "array",
"items": {
"$ref": "#/components/schemas/SuccessBasedRoutingConfigParams"
},
"nullable": true
},
"config": {
"allOf": [
{
"$ref": "#/components/schemas/SuccessBasedRoutingConfigBody"
}
],
"nullable": true
}
}
},
"SuccessBasedRoutingConfigBody": {
"type": "object",
"properties": {
"min_aggregates_size": {
"type": "integer",
"format": "int32",
"nullable": true,
"minimum": 0
},
"default_success_rate": {
"type": "number",
"format": "double",
"nullable": true
},
"max_aggregates_size": {
"type": "integer",
"format": "int32",
"nullable": true,
"minimum": 0
},
"current_block_threshold": {
"allOf": [
{
"$ref": "#/components/schemas/CurrentBlockThreshold"
}
],
"nullable": true
}
}
},
"SuccessBasedRoutingConfigParams": {
"SuccessBasedRoutingFeatures": {
"type": "string",
"enum": [
"PaymentMethod",
"PaymentMethodType",
"Currency",
"AuthenticationType"
"metrics",
"dynamic_connector_selection",
"none"
]
},
"SuccessBasedRoutingUpdateConfigQuery": {
"type": "object",
"required": [
"algorithm_id",
"profile_id"
],
"properties": {
"algorithm_id": {
"type": "string"
},
"profile_id": {
"type": "string"
}
}
},
"SurchargeDetailsResponse": {
"type": "object",
"required": [
Expand Down Expand Up @@ -23961,11 +23797,11 @@
"ToggleSuccessBasedRoutingQuery": {
"type": "object",
"required": [
"status"
"enable"
],
"properties": {
"status": {
"type": "boolean"
"enable": {
"$ref": "#/components/schemas/SuccessBasedRoutingFeatures"
}
}
},
Expand Down
45 changes: 37 additions & 8 deletions crates/api_models/src/routing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -522,22 +522,51 @@ pub struct DynamicAlgorithmWithTimestamp<T> {

#[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize)]
pub struct DynamicRoutingAlgorithmRef {
pub success_based_algorithm:
Option<DynamicAlgorithmWithTimestamp<common_utils::id_type::RoutingId>>,
pub success_based_algorithm: Option<SuccessBasedAlgorithm>,
}

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct SuccessBasedAlgorithm {
pub algorithm_id_with_timestamp:
DynamicAlgorithmWithTimestamp<common_utils::id_type::RoutingId>,
#[serde(default)]
pub enabled_feature: SuccessBasedRoutingFeatures,
}

impl SuccessBasedAlgorithm {
pub fn update_enabled_features(&mut self, feature_to_enable: SuccessBasedRoutingFeatures) {
self.enabled_feature = feature_to_enable
}
}

impl DynamicRoutingAlgorithmRef {
pub fn update_algorithm_id(&mut self, new_id: common_utils::id_type::RoutingId) {
self.success_based_algorithm = Some(DynamicAlgorithmWithTimestamp {
algorithm_id: Some(new_id),
timestamp: common_utils::date_time::now_unix_timestamp(),
pub fn update_algorithm_id(
&mut self,
new_id: common_utils::id_type::RoutingId,
enabled_feature: SuccessBasedRoutingFeatures,
) {
self.success_based_algorithm = Some(SuccessBasedAlgorithm {
algorithm_id_with_timestamp: DynamicAlgorithmWithTimestamp {
algorithm_id: Some(new_id),
timestamp: common_utils::date_time::now_unix_timestamp(),
},
enabled_feature,
})
}
}

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)]
pub struct ToggleSuccessBasedRoutingQuery {
pub status: bool,
pub enable: SuccessBasedRoutingFeatures,
}

#[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum SuccessBasedRoutingFeatures {
Metrics,
DynamicConnectorSelection,
#[default]
None,
}

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)]
Expand All @@ -551,7 +580,7 @@ pub struct SuccessBasedRoutingUpdateConfigQuery {
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
pub struct ToggleSuccessBasedRoutingWrapper {
pub profile_id: common_utils::id_type::ProfileId,
pub status: bool,
pub feature_to_enable: SuccessBasedRoutingFeatures,
}

#[derive(Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)]
Expand Down
7 changes: 1 addition & 6 deletions crates/openapi/src/openapi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,6 @@ Never share your secret api keys. Keep them guarded and secure.
routes::routing::routing_retrieve_default_config_for_profiles,
routes::routing::routing_update_default_config_for_profile,
routes::routing::toggle_success_based_routing,
routes::routing::success_based_routing_update_configs,
// Routes for blocklist
routes::blocklist::remove_entry_from_blocklist,
Expand Down Expand Up @@ -566,6 +565,7 @@ Never share your secret api keys. Keep them guarded and secure.
api_models::routing::RoutingDictionaryRecord,
api_models::routing::RoutingKind,
api_models::routing::RoutableConnectorChoice,
api_models::routing::SuccessBasedRoutingFeatures,
api_models::routing::LinkedRoutingConfigRetrieveResponse,
api_models::routing::RoutingRetrieveResponse,
api_models::routing::ProfileDefaultRoutingConfig,
Expand All @@ -577,11 +577,6 @@ Never share your secret api keys. Keep them guarded and secure.
api_models::routing::ConnectorVolumeSplit,
api_models::routing::ConnectorSelection,
api_models::routing::ToggleSuccessBasedRoutingQuery,
api_models::routing::SuccessBasedRoutingConfig,
api_models::routing::SuccessBasedRoutingConfigParams,
api_models::routing::SuccessBasedRoutingConfigBody,
api_models::routing::CurrentBlockThreshold,
api_models::routing::SuccessBasedRoutingUpdateConfigQuery,
api_models::routing::ToggleSuccessBasedRoutingPath,
api_models::routing::ast::RoutableChoiceKind,
api_models::enums::RoutableConnectors,
Expand Down
29 changes: 1 addition & 28 deletions crates/openapi/src/routes/routing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ pub async fn routing_update_default_config_for_profile() {}
params(
("account_id" = String, Path, description = "Merchant id"),
("profile_id" = String, Path, description = "Profile id under which Dynamic routing needs to be toggled"),
("status" = bool, Query, description = "Boolean value for mentioning the expected state of dynamic routing"),
("enable" = SuccessBasedRoutingFeatures, Query, description = "Feature to enable for success based routing"),
),
responses(
(status = 200, description = "Routing Algorithm created", body = RoutingDictionaryRecord),
Expand All @@ -281,30 +281,3 @@ pub async fn routing_update_default_config_for_profile() {}
security(("api_key" = []), ("jwt_key" = []))
)]
pub async fn toggle_success_based_routing() {}

#[cfg(feature = "v1")]
/// Routing - Update config for success based dynamic routing
///
/// Update config for success based dynamic routing
#[utoipa::path(
patch,
path = "/account/:account_id/business_profile/:profile_id/dynamic_routing/success_based/config/:algorithm_id",
request_body = SuccessBasedRoutingConfig,
params(
("account_id" = String, Path, description = "Merchant id"),
("profile_id" = String, Path, description = "The unique identifier for a profile"),
("algorithm_id" = String, Path, description = "The unique identifier for routing algorithm"),
),
responses(
(status = 200, description = "Routing Algorithm updated", body = RoutingDictionaryRecord),
(status = 400, description = "Request body is malformed"),
(status = 500, description = "Internal server error"),
(status = 404, description = "Resource missing"),
(status = 422, description = "Unprocessable request"),
(status = 403, description = "Forbidden"),
),
tag = "Routing",
operation_id = "Update configs for success based dynamic routing algorithm",
security(("admin_api_key" = []))
)]
pub async fn success_based_routing_update_configs() {}
14 changes: 14 additions & 0 deletions crates/router/src/core/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,20 @@ pub enum RoutingError {
VolumeSplitFailed,
#[error("Unable to parse metadata")]
MetadataParsingError,
#[error("Unable to retrieve success based routing config")]
SuccessBasedRoutingConfigError,
#[error("Unable to calculate success based routing config from dynamic routing service")]
SuccessRateCalculationError,
#[error("Success rate client from dynamic routing gRPC service not initialized")]
SuccessRateClientInitializationError,
#[error("Unable to convert from '{from}' to '{to}'")]
GenericConversionError { from: String, to: String },
#[error("Invalid success based connector label received from dynamic routing service: '{0}'")]
InvalidSuccessBasedConnectorLabel(String),
#[error("unable to find '{field}'")]
GenericNotFoundError { field: String },
#[error("Unable to deserialize from '{from}' to '{to}'")]
DeserializationError { from: String, to: String },
}

#[derive(Debug, Clone, thiserror::Error)]
Expand Down
Loading

0 comments on commit ce732db

Please sign in to comment.