use serde::{Deserialize, Deserializer, Serialize, Serializer};
use super::{ExtensionMap, Metadata};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
#[serde(rename_all = "camelCase")]
pub struct FailureSemantics {
pub id: String,
pub scope: FailureScope,
pub triggers: Vec<String>,
pub responses: Vec<FailureResponse>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub category: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub retry: Option<RetrySemantics>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub compensation: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub recovery: Option<RecoverySemantics>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub metadata: Option<Metadata>,
#[serde(default, flatten)]
pub extensions: ExtensionMap,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
#[serde(rename_all = "camelCase")]
pub struct FailureScope {
pub kind: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub step_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub path: Option<String>,
}
impl FailureScope {
pub fn is_step(&self) -> bool {
self.kind.eq_ignore_ascii_case("step")
}
pub fn pipeline() -> Self {
Self {
kind: "pipeline".to_owned(),
step_id: None,
path: None,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum FailureResponse {
Abort,
Retry,
Compensate,
Continue,
Skip,
AlternatePath,
RequireApproval,
EmitDiagnostics,
Extension(String),
}
impl FailureResponse {
pub fn as_str(&self) -> &str {
match self {
Self::Abort => "abort",
Self::Retry => "retry",
Self::Compensate => "compensate",
Self::Continue => "continue",
Self::Skip => "skip",
Self::AlternatePath => "alternatePath",
Self::RequireApproval => "requireApproval",
Self::EmitDiagnostics => "emitDiagnostics",
Self::Extension(value) => value.as_str(),
}
}
pub fn is_retry(&self) -> bool {
matches!(self, Self::Retry)
}
}
impl Serialize for FailureResponse {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(self.as_str())
}
}
impl<'de> Deserialize<'de> for FailureResponse {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let value = String::deserialize(deserializer)?;
Ok(match value.as_str() {
"abort" => Self::Abort,
"retry" => Self::Retry,
"compensate" => Self::Compensate,
"continue" => Self::Continue,
"skip" => Self::Skip,
"alternatePath" => Self::AlternatePath,
"requireApproval" => Self::RequireApproval,
"emitDiagnostics" => Self::EmitDiagnostics,
other => Self::Extension(other.to_owned()),
})
}
}
#[cfg(feature = "jsonschema")]
impl schemars::JsonSchema for FailureResponse {
fn schema_name() -> String {
"FailureResponse".to_owned()
}
fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
String::json_schema(gen)
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
#[serde(rename_all = "camelCase")]
pub struct RetrySemantics {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub eligible: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub max_attempts: Option<u32>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub conditions: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub delay_policy: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub termination: Option<String>,
#[serde(default, flatten)]
pub extensions: ExtensionMap,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
#[serde(rename_all = "camelCase")]
pub struct RecoverySemantics {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub restart: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub resume: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub rollback: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub checkpoint: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub state_restoration: Option<String>,
#[serde(default, flatten)]
pub extensions: ExtensionMap,
}