Rust Production Deployment Best Practices¶
Objective: Master senior-level Rust production deployment patterns for enterprise systems. When you need to deploy Rust applications to production, when you want to ensure high availability and reliability, when you need enterprise-grade deployment strategiesโthese best practices become your weapon of choice.
Core Principles¶
- Zero Downtime: Deploy without service interruption
- Rolling Updates: Gradual deployment of new versions
- Blue-Green Deployment: Maintain two identical environments
- Canary Releases: Test new versions with a subset of users
- Rollback Strategy: Quick recovery from failed deployments
Production Deployment Patterns¶
Blue-Green Deployment¶
// rust/01-blue-green-deployment.rs
/*
Blue-green deployment patterns and best practices
*/
use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use std::time::{Duration, Instant};
/// Blue-green deployment manager.
pub struct BlueGreenDeployment {
blue_environment: Environment,
green_environment: Environment,
active_environment: EnvironmentType,
deployment_config: DeploymentConfig,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Environment {
pub name: String,
pub version: String,
pub status: EnvironmentStatus,
pub health_check_url: String,
pub load_balancer_weight: u32,
pub instances: Vec<Instance>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum EnvironmentStatus {
Healthy,
Unhealthy,
Deploying,
Deployed,
Failed,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum EnvironmentType {
Blue,
Green,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Instance {
pub id: String,
pub status: InstanceStatus,
pub health_check_url: String,
pub load_balancer_weight: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum InstanceStatus {
Healthy,
Unhealthy,
Starting,
Stopping,
Stopped,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeploymentConfig {
pub health_check_timeout: Duration,
pub health_check_interval: Duration,
pub max_health_check_attempts: u32,
pub rollback_timeout: Duration,
pub load_balancer_switch_delay: Duration,
}
impl BlueGreenDeployment {
pub fn new(config: DeploymentConfig) -> Self {
Self {
blue_environment: Environment {
name: "blue".to_string(),
version: "1.0.0".to_string(),
status: EnvironmentStatus::Healthy,
health_check_url: "http://blue.example.com/health".to_string(),
load_balancer_weight: 100,
instances: Vec::new(),
},
green_environment: Environment {
name: "green".to_string(),
version: "1.0.0".to_string(),
status: EnvironmentStatus::Healthy,
health_check_url: "http://green.example.com/health".to_string(),
load_balancer_weight: 0,
instances: Vec::new(),
},
active_environment: EnvironmentType::Blue,
deployment_config: config,
}
}
/// Deploy a new version using blue-green deployment.
pub async fn deploy(&mut self, new_version: String) -> Result<DeploymentResult, String> {
let start_time = Instant::now();
// Determine which environment to deploy to
let target_environment = match self.active_environment {
EnvironmentType::Blue => &mut self.green_environment,
EnvironmentType::Green => &mut self.blue_environment,
};
// Deploy to inactive environment
target_environment.status = EnvironmentStatus::Deploying;
target_environment.version = new_version.clone();
// Deploy instances
self.deploy_instances(target_environment).await?;
// Wait for health checks
self.wait_for_health_checks(target_environment).await?;
// Switch traffic to new environment
self.switch_traffic().await?;
// Update active environment
self.active_environment = match self.active_environment {
EnvironmentType::Blue => EnvironmentType::Green,
EnvironmentType::Green => EnvironmentType::Blue,
};
let duration = start_time.elapsed();
Ok(DeploymentResult {
success: true,
duration,
new_version,
active_environment: self.active_environment.clone(),
})
}
/// Deploy instances to an environment.
async fn deploy_instances(&self, environment: &mut Environment) -> Result<(), String> {
// In a real implementation, you would deploy instances using
// Kubernetes, Docker Swarm, or other orchestration platform
println!("Deploying instances to {} environment", environment.name);
// Simulate deployment
tokio::time::sleep(Duration::from_secs(5)).await;
// Create instances
environment.instances = vec![
Instance {
id: "instance-1".to_string(),
status: InstanceStatus::Starting,
health_check_url: format!("{}/health", environment.health_check_url),
load_balancer_weight: 50,
},
Instance {
id: "instance-2".to_string(),
status: InstanceStatus::Starting,
health_check_url: format!("{}/health", environment.health_check_url),
load_balancer_weight: 50,
},
];
Ok(())
}
/// Wait for health checks to pass.
async fn wait_for_health_checks(&self, environment: &mut Environment) -> Result<(), String> {
let mut attempts = 0;
while attempts < self.deployment_config.max_health_check_attempts {
// Check health of all instances
let mut all_healthy = true;
for instance in &mut environment.instances {
if self.check_instance_health(instance).await? {
instance.status = InstanceStatus::Healthy;
} else {
instance.status = InstanceStatus::Unhealthy;
all_healthy = false;
}
}
if all_healthy {
environment.status = EnvironmentStatus::Healthy;
return Ok(());
}
attempts += 1;
tokio::time::sleep(self.deployment_config.health_check_interval).await;
}
environment.status = EnvironmentStatus::Failed;
Err("Health checks failed".to_string())
}
/// Check health of a single instance.
async fn check_instance_health(&self, instance: &Instance) -> Result<bool, String> {
// In a real implementation, you would make an HTTP request
// to the health check URL
println!("Checking health of instance {}", instance.id);
// Simulate health check
tokio::time::sleep(Duration::from_millis(100)).await;
// For this example, assume all instances are healthy
Ok(true)
}
/// Switch traffic to the new environment.
async fn switch_traffic(&mut self) -> Result<(), String> {
// In a real implementation, you would update load balancer
// configuration to route traffic to the new environment
let (blue_weight, green_weight) = match self.active_environment {
EnvironmentType::Blue => (100, 0),
EnvironmentType::Green => (0, 100),
};
self.blue_environment.load_balancer_weight = blue_weight;
self.green_environment.load_balancer_weight = green_weight;
// Wait for load balancer to switch
tokio::time::sleep(self.deployment_config.load_balancer_switch_delay).await;
Ok(())
}
/// Rollback to the previous environment.
pub async fn rollback(&mut self) -> Result<DeploymentResult, String> {
let start_time = Instant::now();
// Switch back to the previous environment
self.active_environment = match self.active_environment {
EnvironmentType::Blue => EnvironmentType::Green,
EnvironmentType::Green => EnvironmentType::Blue,
};
// Switch traffic back
self.switch_traffic().await?;
let duration = start_time.elapsed();
Ok(DeploymentResult {
success: true,
duration,
new_version: "rollback".to_string(),
active_environment: self.active_environment.clone(),
})
}
/// Get deployment status.
pub fn get_status(&self) -> DeploymentStatus {
DeploymentStatus {
active_environment: self.active_environment.clone(),
blue_environment: self.blue_environment.clone(),
green_environment: self.green_environment.clone(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeploymentResult {
pub success: bool,
pub duration: Duration,
pub new_version: String,
pub active_environment: EnvironmentType,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeploymentStatus {
pub active_environment: EnvironmentType,
pub blue_environment: Environment,
pub green_environment: Environment,
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_blue_green_deployment() {
let config = DeploymentConfig {
health_check_timeout: Duration::from_secs(30),
health_check_interval: Duration::from_secs(5),
max_health_check_attempts: 6,
rollback_timeout: Duration::from_secs(60),
load_balancer_switch_delay: Duration::from_secs(10),
};
let mut deployment = BlueGreenDeployment::new(config);
let result = deployment.deploy("2.0.0".to_string()).await;
assert!(result.is_ok());
assert!(result.unwrap().success);
}
#[tokio::test]
async fn test_rollback() {
let config = DeploymentConfig {
health_check_timeout: Duration::from_secs(30),
health_check_interval: Duration::from_secs(5),
max_health_check_attempts: 6,
rollback_timeout: Duration::from_secs(60),
load_balancer_switch_delay: Duration::from_secs(10),
};
let mut deployment = BlueGreenDeployment::new(config);
let result = deployment.rollback().await;
assert!(result.is_ok());
assert!(result.unwrap().success);
}
}
Canary Deployment¶
// rust/02-canary-deployment.rs
/*
Canary deployment patterns and best practices
*/
use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use std::time::{Duration, Instant};
/// Canary deployment manager.
pub struct CanaryDeployment {
stable_environment: Environment,
canary_environment: Environment,
canary_percentage: u32,
deployment_config: DeploymentConfig,
metrics: CanaryMetrics,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CanaryMetrics {
pub error_rate: f64,
pub response_time: Duration,
pub throughput: f64,
pub cpu_usage: f64,
pub memory_usage: f64,
}
impl CanaryDeployment {
pub fn new(config: DeploymentConfig) -> Self {
Self {
stable_environment: Environment {
name: "stable".to_string(),
version: "1.0.0".to_string(),
status: EnvironmentStatus::Healthy,
health_check_url: "http://stable.example.com/health".to_string(),
load_balancer_weight: 100,
instances: Vec::new(),
},
canary_environment: Environment {
name: "canary".to_string(),
version: "1.0.0".to_string(),
status: EnvironmentStatus::Healthy,
health_check_url: "http://canary.example.com/health".to_string(),
load_balancer_weight: 0,
instances: Vec::new(),
},
canary_percentage: 0,
deployment_config: config,
metrics: CanaryMetrics {
error_rate: 0.0,
response_time: Duration::from_millis(100),
throughput: 1000.0,
cpu_usage: 50.0,
memory_usage: 60.0,
},
}
}
/// Deploy a new version using canary deployment.
pub async fn deploy(&mut self, new_version: String, initial_percentage: u32) -> Result<DeploymentResult, String> {
let start_time = Instant::now();
// Deploy to canary environment
self.canary_environment.status = EnvironmentStatus::Deploying;
self.canary_environment.version = new_version.clone();
// Deploy instances
self.deploy_instances(&mut self.canary_environment).await?;
// Wait for health checks
self.wait_for_health_checks(&mut self.canary_environment).await?;
// Start with initial canary percentage
self.canary_percentage = initial_percentage;
self.update_load_balancer_weights().await?;
// Monitor canary metrics
self.monitor_canary_metrics().await?;
let duration = start_time.elapsed();
Ok(DeploymentResult {
success: true,
duration,
new_version,
active_environment: EnvironmentType::Blue, // Not applicable for canary
})
}
/// Deploy instances to an environment.
async fn deploy_instances(&self, environment: &mut Environment) -> Result<(), String> {
// In a real implementation, you would deploy instances using
// Kubernetes, Docker Swarm, or other orchestration platform
println!("Deploying instances to {} environment", environment.name);
// Simulate deployment
tokio::time::sleep(Duration::from_secs(5)).await;
// Create instances
environment.instances = vec![
Instance {
id: "instance-1".to_string(),
status: InstanceStatus::Starting,
health_check_url: format!("{}/health", environment.health_check_url),
load_balancer_weight: 50,
},
];
Ok(())
}
/// Wait for health checks to pass.
async fn wait_for_health_checks(&self, environment: &mut Environment) -> Result<(), String> {
let mut attempts = 0;
while attempts < self.deployment_config.max_health_check_attempts {
// Check health of all instances
let mut all_healthy = true;
for instance in &mut environment.instances {
if self.check_instance_health(instance).await? {
instance.status = InstanceStatus::Healthy;
} else {
instance.status = InstanceStatus::Unhealthy;
all_healthy = false;
}
}
if all_healthy {
environment.status = EnvironmentStatus::Healthy;
return Ok(());
}
attempts += 1;
tokio::time::sleep(self.deployment_config.health_check_interval).await;
}
environment.status = EnvironmentStatus::Failed;
Err("Health checks failed".to_string())
}
/// Check health of a single instance.
async fn check_instance_health(&self, instance: &Instance) -> Result<bool, String> {
// In a real implementation, you would make an HTTP request
// to the health check URL
println!("Checking health of instance {}", instance.id);
// Simulate health check
tokio::time::sleep(Duration::from_millis(100)).await;
// For this example, assume all instances are healthy
Ok(true)
}
/// Update load balancer weights based on canary percentage.
async fn update_load_balancer_weights(&mut self) -> Result<(), String> {
let stable_weight = 100 - self.canary_percentage;
let canary_weight = self.canary_percentage;
self.stable_environment.load_balancer_weight = stable_weight;
self.canary_environment.load_balancer_weight = canary_weight;
println!("Updated load balancer weights: stable={}%, canary={}%", stable_weight, canary_weight);
Ok(())
}
/// Monitor canary metrics and make decisions.
async fn monitor_canary_metrics(&mut self) -> Result<(), String> {
// In a real implementation, you would collect metrics from
// monitoring systems like Prometheus, DataDog, etc.
// Simulate metric collection
self.metrics.error_rate = 0.01; // 1% error rate
self.metrics.response_time = Duration::from_millis(150);
self.metrics.throughput = 1200.0;
self.metrics.cpu_usage = 55.0;
self.metrics.memory_usage = 65.0;
// Check if metrics are within acceptable ranges
if self.metrics.error_rate > 0.05 { // 5% error rate threshold
return Err("Canary deployment failed: error rate too high".to_string());
}
if self.metrics.response_time > Duration::from_millis(500) {
return Err("Canary deployment failed: response time too high".to_string());
}
if self.metrics.cpu_usage > 80.0 {
return Err("Canary deployment failed: CPU usage too high".to_string());
}
if self.metrics.memory_usage > 90.0 {
return Err("Canary deployment failed: memory usage too high".to_string());
}
Ok(())
}
/// Increase canary percentage.
pub async fn increase_canary_percentage(&mut self, percentage: u32) -> Result<(), String> {
self.canary_percentage = (self.canary_percentage + percentage).min(100);
self.update_load_balancer_weights().await?;
// Monitor metrics after increase
self.monitor_canary_metrics().await?;
Ok(())
}
/// Promote canary to stable.
pub async fn promote_canary(&mut self) -> Result<(), String> {
// Switch all traffic to canary
self.canary_percentage = 100;
self.update_load_balancer_weights().await?;
// Wait for traffic to stabilize
tokio::time::sleep(Duration::from_secs(30)).await;
// Update stable environment
self.stable_environment.version = self.canary_environment.version.clone();
self.stable_environment.instances = self.canary_environment.instances.clone();
// Reset canary
self.canary_percentage = 0;
self.update_load_balancer_weights().await?;
Ok(())
}
/// Rollback canary deployment.
pub async fn rollback_canary(&mut self) -> Result<(), String> {
// Set canary percentage to 0
self.canary_percentage = 0;
self.update_load_balancer_weights().await?;
// Stop canary instances
for instance in &mut self.canary_environment.instances {
instance.status = InstanceStatus::Stopped;
}
Ok(())
}
/// Get canary metrics.
pub fn get_metrics(&self) -> &CanaryMetrics {
&self.metrics
}
/// Get canary status.
pub fn get_status(&self) -> CanaryStatus {
CanaryStatus {
canary_percentage: self.canary_percentage,
stable_environment: self.stable_environment.clone(),
canary_environment: self.canary_environment.clone(),
metrics: self.metrics.clone(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CanaryStatus {
pub canary_percentage: u32,
pub stable_environment: Environment,
pub canary_environment: Environment,
pub metrics: CanaryMetrics,
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_canary_deployment() {
let config = DeploymentConfig {
health_check_timeout: Duration::from_secs(30),
health_check_interval: Duration::from_secs(5),
max_health_check_attempts: 6,
rollback_timeout: Duration::from_secs(60),
load_balancer_switch_delay: Duration::from_secs(10),
};
let mut deployment = CanaryDeployment::new(config);
let result = deployment.deploy("2.0.0".to_string(), 10).await;
assert!(result.is_ok());
assert!(result.unwrap().success);
}
#[tokio::test]
async fn test_increase_canary_percentage() {
let config = DeploymentConfig {
health_check_timeout: Duration::from_secs(30),
health_check_interval: Duration::from_secs(5),
max_health_check_attempts: 6,
rollback_timeout: Duration::from_secs(60),
load_balancer_switch_delay: Duration::from_secs(10),
};
let mut deployment = CanaryDeployment::new(config);
deployment.deploy("2.0.0".to_string(), 10).await.unwrap();
let result = deployment.increase_canary_percentage(20).await;
assert!(result.is_ok());
assert_eq!(deployment.canary_percentage, 30);
}
#[tokio::test]
async fn test_promote_canary() {
let config = DeploymentConfig {
health_check_timeout: Duration::from_secs(30),
health_check_interval: Duration::from_secs(5),
max_health_check_attempts: 6,
rollback_timeout: Duration::from_secs(60),
load_balancer_switch_delay: Duration::from_secs(10),
};
let mut deployment = CanaryDeployment::new(config);
deployment.deploy("2.0.0".to_string(), 10).await.unwrap();
let result = deployment.promote_canary().await;
assert!(result.is_ok());
assert_eq!(deployment.canary_percentage, 0);
}
}
Rolling Updates¶
// rust/03-rolling-updates.rs
/*
Rolling update patterns and best practices
*/
use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use std::time::{Duration, Instant};
/// Rolling update manager.
pub struct RollingUpdateManager {
instances: Vec<Instance>,
new_version: String,
update_config: UpdateConfig,
update_status: UpdateStatus,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UpdateConfig {
pub max_unavailable: u32,
pub max_surge: u32,
pub update_timeout: Duration,
pub health_check_timeout: Duration,
pub health_check_interval: Duration,
pub max_health_check_attempts: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum UpdateStatus {
NotStarted,
InProgress,
Completed,
Failed,
RollingBack,
}
impl RollingUpdateManager {
pub fn new(instances: Vec<Instance>, new_version: String, config: UpdateConfig) -> Self {
Self {
instances,
new_version,
update_config: config,
update_status: UpdateStatus::NotStarted,
}
}
/// Start rolling update.
pub async fn start_update(&mut self) -> Result<UpdateResult, String> {
let start_time = Instant::now();
self.update_status = UpdateStatus::InProgress;
// Calculate update strategy
let strategy = self.calculate_update_strategy()?;
// Update instances in batches
for batch in strategy.batches {
self.update_batch(batch).await?;
}
self.update_status = UpdateStatus::Completed;
let duration = start_time.elapsed();
Ok(UpdateResult {
success: true,
duration,
updated_instances: self.instances.len(),
failed_instances: 0,
})
}
/// Calculate update strategy.
fn calculate_update_strategy(&self) -> Result<UpdateStrategy, String> {
let total_instances = self.instances.len() as u32;
let max_unavailable = self.update_config.max_unavailable;
let max_surge = self.update_config.max_surge;
// Calculate batch size
let batch_size = if max_unavailable > 0 {
(total_instances - max_unavailable).min(max_surge)
} else {
max_surge
};
if batch_size == 0 {
return Err("Invalid update configuration".to_string());
}
// Create batches
let mut batches = Vec::new();
let mut remaining_instances = total_instances;
while remaining_instances > 0 {
let current_batch_size = batch_size.min(remaining_instances);
batches.push(current_batch_size);
remaining_instances -= current_batch_size;
}
Ok(UpdateStrategy { batches })
}
/// Update a batch of instances.
async fn update_batch(&mut self, batch_size: u32) -> Result<(), String> {
let mut updated_count = 0;
for instance in &mut self.instances {
if updated_count >= batch_size {
break;
}
if instance.status == InstanceStatus::Healthy {
// Update instance
self.update_instance(instance).await?;
updated_count += 1;
}
}
// Wait for batch to be healthy
self.wait_for_batch_health().await?;
Ok(())
}
/// Update a single instance.
async fn update_instance(&self, instance: &mut Instance) -> Result<(), String> {
println!("Updating instance {}", instance.id);
// In a real implementation, you would:
// 1. Deploy new version to instance
// 2. Update load balancer configuration
// 3. Wait for instance to be ready
// Simulate update
instance.status = InstanceStatus::Starting;
tokio::time::sleep(Duration::from_secs(2)).await;
// Check health
if self.check_instance_health(instance).await? {
instance.status = InstanceStatus::Healthy;
} else {
instance.status = InstanceStatus::Unhealthy;
return Err("Instance health check failed".to_string());
}
Ok(())
}
/// Check health of a single instance.
async fn check_instance_health(&self, instance: &Instance) -> Result<bool, String> {
// In a real implementation, you would make an HTTP request
// to the health check URL
println!("Checking health of instance {}", instance.id);
// Simulate health check
tokio::time::sleep(Duration::from_millis(100)).await;
// For this example, assume all instances are healthy
Ok(true)
}
/// Wait for batch to be healthy.
async fn wait_for_batch_health(&self) -> Result<(), String> {
let mut attempts = 0;
while attempts < self.update_config.max_health_check_attempts {
let mut all_healthy = true;
for instance in &self.instances {
if instance.status == InstanceStatus::Starting {
if !self.check_instance_health(instance).await? {
all_healthy = false;
break;
}
}
}
if all_healthy {
return Ok(());
}
attempts += 1;
tokio::time::sleep(self.update_config.health_check_interval).await;
}
Err("Batch health check failed".to_string())
}
/// Rollback update.
pub async fn rollback(&mut self) -> Result<UpdateResult, String> {
let start_time = Instant::now();
self.update_status = UpdateStatus::RollingBack;
// Rollback all instances
for instance in &mut self.instances {
if instance.status == InstanceStatus::Healthy {
self.rollback_instance(instance).await?;
}
}
self.update_status = UpdateStatus::Completed;
let duration = start_time.elapsed();
Ok(UpdateResult {
success: true,
duration,
updated_instances: 0,
failed_instances: 0,
})
}
/// Rollback a single instance.
async fn rollback_instance(&self, instance: &mut Instance) -> Result<(), String> {
println!("Rolling back instance {}", instance.id);
// In a real implementation, you would:
// 1. Deploy previous version to instance
// 2. Update load balancer configuration
// 3. Wait for instance to be ready
// Simulate rollback
instance.status = InstanceStatus::Starting;
tokio::time::sleep(Duration::from_secs(2)).await;
// Check health
if self.check_instance_health(instance).await? {
instance.status = InstanceStatus::Healthy;
} else {
instance.status = InstanceStatus::Unhealthy;
return Err("Instance rollback failed".to_string());
}
Ok(())
}
/// Get update status.
pub fn get_status(&self) -> &UpdateStatus {
&self.update_status
}
/// Get instance status.
pub fn get_instance_status(&self) -> Vec<&Instance> {
self.instances.iter().collect()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UpdateStrategy {
pub batches: Vec<u32>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UpdateResult {
pub success: bool,
pub duration: Duration,
pub updated_instances: usize,
pub failed_instances: usize,
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_rolling_update() {
let instances = vec![
Instance {
id: "instance-1".to_string(),
status: InstanceStatus::Healthy,
health_check_url: "http://instance-1.example.com/health".to_string(),
load_balancer_weight: 50,
},
Instance {
id: "instance-2".to_string(),
status: InstanceStatus::Healthy,
health_check_url: "http://instance-2.example.com/health".to_string(),
load_balancer_weight: 50,
},
];
let config = UpdateConfig {
max_unavailable: 1,
max_surge: 1,
update_timeout: Duration::from_secs(300),
health_check_timeout: Duration::from_secs(30),
health_check_interval: Duration::from_secs(5),
max_health_check_attempts: 6,
};
let mut manager = RollingUpdateManager::new(instances, "2.0.0".to_string(), config);
let result = manager.start_update().await;
assert!(result.is_ok());
assert!(result.unwrap().success);
}
#[tokio::test]
async fn test_rollback() {
let instances = vec![
Instance {
id: "instance-1".to_string(),
status: InstanceStatus::Healthy,
health_check_url: "http://instance-1.example.com/health".to_string(),
load_balancer_weight: 50,
},
];
let config = UpdateConfig {
max_unavailable: 1,
max_surge: 1,
update_timeout: Duration::from_secs(300),
health_check_timeout: Duration::from_secs(30),
health_check_interval: Duration::from_secs(5),
max_health_check_attempts: 6,
};
let mut manager = RollingUpdateManager::new(instances, "2.0.0".to_string(), config);
let result = manager.rollback().await;
assert!(result.is_ok());
assert!(result.unwrap().success);
}
}
TL;DR Runbook¶
Quick Start¶
// 1. Blue-green deployment
let config = DeploymentConfig { /* ... */ };
let mut deployment = BlueGreenDeployment::new(config);
deployment.deploy("2.0.0".to_string()).await?;
// 2. Canary deployment
let mut canary = CanaryDeployment::new(config);
canary.deploy("2.0.0".to_string(), 10).await?;
canary.increase_canary_percentage(20).await?;
// 3. Rolling updates
let mut manager = RollingUpdateManager::new(instances, "2.0.0".to_string(), config);
manager.start_update().await?;
Essential Patterns¶
// Complete production deployment setup
pub fn setup_rust_production_deployment() {
// 1. Blue-green deployment
// 2. Canary deployment
// 3. Rolling updates
// 4. Health checks
// 5. Rollback strategies
// 6. Load balancing
// 7. Monitoring
// 8. Alerting
println!("Rust production deployment setup complete!");
}
This guide provides the complete machinery for Rust production deployment. Each pattern includes implementation examples, deployment strategies, and real-world usage patterns for enterprise production systems.