use thiserror::Error;
pub type ActuatorResult<T> = Result<T, ActuatorError>;
#[derive(Error, Debug, Clone, PartialEq)]
pub enum ActuatorError {
#[error("Configuration error: {0}")]
ConfigError(String),
#[error("Deployment failed: {0}")]
DeploymentFailed(String),
#[error("Rollback failed: {0}")]
RollbackFailed(String),
#[error("Health check failed: {0}")]
HealthCheckFailed(String),
#[error("Validation failed: {0}")]
ValidationFailed(String),
#[error("Traffic splitting error: {0}")]
TrafficSplitError(String),
#[error("State error: {0}")]
StateError(String),
#[error("Actuator is not running")]
NotRunning,
#[error("Invalid state transition from {from:?} to {to:?}")]
InvalidStateTransition {
from: ActuatorState,
to: ActuatorState,
},
#[error("Operation timeout after {0}ms")]
Timeout(u64),
#[error("Internal error: {0}")]
Internal(String),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ActuatorState {
Initialized,
Starting,
Running,
Deploying,
RollingBack,
Draining,
Stopped,
Failed,
}
impl ActuatorState {
pub fn can_deploy(&self) -> bool {
matches!(self, ActuatorState::Running)
}
pub fn can_rollback(&self) -> bool {
matches!(self, ActuatorState::Running | ActuatorState::Deploying)
}
pub fn can_transition_to(&self, to: ActuatorState) -> bool {
use ActuatorState::*;
matches!(
(self, to),
(Initialized, Starting)
| (Starting, Running)
| (Starting, Failed)
| (Running, Deploying)
| (Running, RollingBack)
| (Running, Draining)
| (Running, Failed)
| (Deploying, Running)
| (Deploying, RollingBack)
| (Deploying, Failed)
| (RollingBack, Running)
| (RollingBack, Failed)
| (Draining, Stopped)
| (Draining, Failed)
| (Failed, Initialized)
)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
pub enum DeploymentState {
Pending,
Validating,
RollingOut,
Monitoring,
Completed,
RollingBack,
RolledBack,
Failed,
}
impl DeploymentState {
pub fn is_terminal(&self) -> bool {
matches!(
self,
DeploymentState::Completed
| DeploymentState::RolledBack
| DeploymentState::Failed
)
}
pub fn can_rollback(&self) -> bool {
matches!(
self,
DeploymentState::RollingOut | DeploymentState::Monitoring
)
}
}
impl std::fmt::Display for DeploymentState {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
DeploymentState::Pending => write!(f, "Pending"),
DeploymentState::Validating => write!(f, "Validating"),
DeploymentState::RollingOut => write!(f, "RollingOut"),
DeploymentState::Monitoring => write!(f, "Monitoring"),
DeploymentState::Completed => write!(f, "Completed"),
DeploymentState::RollingBack => write!(f, "RollingBack"),
DeploymentState::RolledBack => write!(f, "RolledBack"),
DeploymentState::Failed => write!(f, "Failed"),
}
}
}