//! Production deployment example demonstrating comprehensive deployment utilities //! //! This example shows how to: //! 1. Set up a model registry with versioning //! 2. Configure environment-specific settings with hot-reloading //! 3. Implement monitoring and observability //! 4. Deploy models with proper health checks //! //! Run with: cargo run --example production_deployment use anyhow::Result; use rtx_config::{create_production_config_manager, ConfigValue, Environment}; use rtx_hub::{ModelRegistry, RegistryConfig, ModelId, ModelVersion, ModelMetadata, ModelStatus, StorageConfig}; use rtx_monitoring::{create_production_monitoring, MonitoringSystem}; use serde_json::json; use std::path::PathBuf; use std::collections::HashMap; use tokio::time::{sleep, Duration}; use tracing::{info, warn, error}; #[tokio::main] async fn main() -> Result<()> { // Initialize tracing tracing_subscriber::fmt() .with_env_filter("info,production_deployment=debug") .init(); info!("🚀 Starting RTX Production Deployment Example"); // 1. Initialize configuration management with hot-reloading let config_manager = setup_configuration().await?; // 2. Set up model registry for versioning and deployment let model_registry = setup_model_registry(&config_manager).await?; // 3. Initialize monitoring and observability let monitoring = setup_monitoring(&config_manager).await?; // 4. Deploy and register example models deploy_example_models(&model_registry).await?; // 5. Run health checks and monitoring run_production_checks(&model_registry, &monitoring).await?; // 6. Demonstrate hot configuration reloading demonstrate_hot_reload(&config_manager).await?; // 7. Show metrics and health status show_system_status(&monitoring).await?; info!("✅ Production deployment example completed successfully"); Ok(()) } /// Set up production configuration with environment-specific settings async fn setup_configuration() -> Result { info!("📋 Setting up configuration management..."); // Create production configuration manager let config_manager = create_production_config_manager().await?; // Set some example production settings config_manager.set("database.pool_size", ConfigValue::Integer(20)).await?; config_manager.set("model_cache.max_size", ConfigValue::String("10GB".to_string())).await?; config_manager.set("inference.batch_size", ConfigValue::Integer(32)).await?; config_manager.set("monitoring.metrics_enabled", ConfigValue::Boolean(true)).await?; // Environment-specific overrides let environment = config_manager.environment(); match environment { Environment::Production => { config_manager.set("log_level", ConfigValue::String("warn".to_string())).await?; config_manager.set("debug_mode", ConfigValue::Boolean(false)).await?; } Environment::Staging => { config_manager.set("log_level", ConfigValue::String("info".to_string())).await?; config_manager.set("debug_mode", ConfigValue::Boolean(true)).await?; } _ => { config_manager.set("log_level", ConfigValue::String("debug".to_string())).await?; config_manager.set("debug_mode", ConfigValue::Boolean(true)).await?; } } // Subscribe to configuration changes for hot-reloading let mut change_receiver = config_manager.subscribe_to_changes(); let config_clone = std::sync::Arc::clone(&config_manager); tokio::spawn(async move { while let Ok(change) = change_receiver.recv().await { info!("🔄 Configuration changed: {} = {:?}", change.key, change.new_value); // Handle specific configuration changes match change.key.as_str() { "inference.batch_size" => { info!("📊 Updating inference batch size..."); // In a real deployment, this would trigger model reload } "monitoring.metrics_enabled" => { info!("📈 Updating metrics collection settings..."); // Toggle metrics collection } _ => {} } } }); info!("✅ Configuration management initialized for environment: {}", environment); Ok(std::sync::Arc::new(config_manager)) } /// Set up model registry for version management async fn setup_model_registry( config_manager: &rtx_config::ConfigManager ) -> Result> { info!("🗄️ Setting up model registry..."); // Get storage configuration from config manager let storage_path = config_manager.get::("storage.models_path") .await .unwrap_or_else(|_| "/tmp/rtx-models".to_string()); let registry_config = RegistryConfig { storage: StorageConfig::Local { base_path: PathBuf::from(storage_path), }, database_url: config_manager.get::("database.url") .await .unwrap_or_else(|_| "sqlite::memory:".to_string()), enable_validation: true, enable_compression: true, max_package_size: Some(5 * 1024 * 1024 * 1024), // 5GB retention_days: Some(365), enable_signing: false, registry_name: Some("RTX Production Registry".to_string()), description: Some("Production model registry for RTX deployments".to_string()), registry_url: None, }; let registry = ModelRegistry::new(registry_config).await?; info!("✅ Model registry initialized"); Ok(std::sync::Arc::new(registry)) } /// Set up comprehensive monitoring and observability async fn setup_monitoring( _config_manager: &rtx_config::ConfigManager ) -> Result> { info!("📊 Setting up monitoring and observability..."); let monitoring = create_production_monitoring().await?; // In a real deployment, you would: // 1. Configure Prometheus endpoints // 2. Set up OpenTelemetry tracing // 3. Configure alerting rules // 4. Set up dashboards info!("✅ Monitoring system initialized"); info!("📈 Metrics available at: http://localhost:9090/metrics"); info!("🏥 Health checks available at: http://localhost:8080/health"); Ok(monitoring) } /// Deploy example models with proper versioning async fn deploy_example_models(registry: &ModelRegistry) -> Result<()> { info!("🤖 Deploying example models..."); // Deploy BERT model v1.0.0 let bert_id = ModelId::new("huggingface", "bert-base-uncased"); let bert_v1 = ModelVersion::parse("1.0.0")?; let bert_metadata = create_model_metadata( bert_id.clone(), bert_v1.clone(), "BERT Base Uncased", "Pre-trained BERT model for natural language understanding", "transformer", &["nlp", "classification", "embeddings"], ); registry.register_model(bert_metadata).await?; info!("✅ Deployed BERT v1.0.0"); // Deploy GPT model v2.1.0 let gpt_id = ModelId::new("openai", "gpt-3.5-turbo"); let gpt_v2 = ModelVersion::parse("2.1.0")?; let gpt_metadata = create_model_metadata( gpt_id.clone(), gpt_v2.clone(), "GPT-3.5 Turbo", "Large language model optimized for chat and instruction following", "transformer", &["nlp", "generation", "chat"], ); registry.register_model(gpt_metadata).await?; info!("✅ Deployed GPT-3.5 v2.1.0"); // Deploy ResNet model v1.2.3 let resnet_id = ModelId::new("torchvision", "resnet50"); let resnet_v1 = ModelVersion::parse("1.2.3")?; let resnet_metadata = create_model_metadata( resnet_id.clone(), resnet_v1.clone(), "ResNet-50", "Deep residual network for image classification", "cnn", &["vision", "classification", "imagenet"], ); registry.register_model(resnet_metadata).await?; info!("✅ Deployed ResNet-50 v1.2.3"); // Show registry statistics let stats = registry.get_stats().await?; info!("📊 Registry Statistics:"); info!(" - Total Models: {}", stats.model_count); info!(" - Total Versions: {}", stats.version_count); info!(" - Total Size: {:.2} MB", stats.total_size as f64 / (1024.0 * 1024.0)); info!(" - Downloads: {}", stats.download_count); Ok(()) } /// Run production health checks and monitoring async fn run_production_checks( registry: &ModelRegistry, monitoring: &MonitoringSystem, ) -> Result<()> { info!("🏥 Running production health checks..."); // Check model registry health let registry_stats = registry.get_stats().await?; if registry_stats.model_count > 0 { info!("✅ Model registry: {} models available", registry_stats.model_count); } else { warn!("⚠️ Model registry: No models found"); } // Check monitoring system health let metrics_summary = monitoring.get_metrics_summary().await?; info!("✅ Monitoring system: {} active alerts", metrics_summary.active_alerts); info!("⏱️ System uptime: {:?}", metrics_summary.uptime); // Simulate some model inference metrics simulate_model_usage(®istry, &monitoring).await?; Ok(()) } /// Demonstrate hot configuration reloading async fn demonstrate_hot_reload(config_manager: &rtx_config::ConfigManager) -> Result<()> { info!("🔄 Demonstrating hot configuration reload..."); // Show current batch size let current_batch_size = config_manager.get::("inference.batch_size").await?; info!("Current batch size: {}", current_batch_size); // Simulate configuration change (in production, this would come from file/env changes) config_manager.set("inference.batch_size", ConfigValue::Integer(64)).await?; // Wait a moment for the change to propagate sleep(Duration::from_millis(100)).await; let new_batch_size = config_manager.get::("inference.batch_size").await?; info!("Updated batch size: {}", new_batch_size); // Revert back config_manager.set("inference.batch_size", ConfigValue::Integer(32)).await?; Ok(()) } /// Show comprehensive system status async fn show_system_status(monitoring: &MonitoringSystem) -> Result<()> { info!("📈 System Status Summary:"); let summary = monitoring.get_metrics_summary().await?; info!("🖥️ System Metrics:"); info!(" - CPU Usage: {:.1}%", summary.system_metrics.cpu_usage); info!(" - Memory Usage: {:.1}%", summary.system_metrics.memory_usage); info!(" - Disk Usage: {:.1}%", summary.system_metrics.disk_usage); info!("🏥 Health Status: {:?}", summary.health_status); info!("🚨 Active Alerts: {}", summary.active_alerts); info!("⏱️ Uptime: {:?}", summary.uptime); // Show available endpoints info!("🌐 Available Endpoints:"); info!(" - Metrics: http://localhost:9090/metrics"); info!(" - Health: http://localhost:8080/health"); info!(" - Model Registry API: http://localhost:8080/api/models"); Ok(()) } /// Simulate model usage for metrics demonstration async fn simulate_model_usage( registry: &ModelRegistry, _monitoring: &MonitoringSystem, ) -> Result<()> { info!("🎯 Simulating model inference requests..."); // Get list of available models let models = registry.list_models(Default::default()).await?; for model in models.iter().take(3) { info!("📊 Processing requests for: {}", model.metadata.id); // Simulate inference requests for i in 1..=5 { // In a real system, this would: // 1. Load the model if not cached // 2. Run inference // 3. Record metrics (latency, throughput, errors) // 4. Update health status sleep(Duration::from_millis(50)).await; // Simulate processing time if i % 10 == 0 { info!(" Processed {} requests", i); } } // Simulate accessing the model (updates access statistics) let mut model_info = registry.get_model(&model.metadata.id, Some(&model.metadata.version)).await?; info!(" Access count: {}", model_info.access_count); } Ok(()) } /// Create model metadata for registration fn create_model_metadata( id: ModelId, version: ModelVersion, title: &str, description: &str, architecture: &str, tags: &[&str], ) -> ModelMetadata { ModelMetadata { id, version, title: title.to_string(), description: description.to_string(), architecture: architecture.to_string(), framework: "rustytorch".to_string(), framework_version: "1.0.0".to_string(), tags: tags.iter().map(|&s| s.to_string()).collect(), author: "RTX Team".to_string(), license: Some("MIT".to_string()), created_at: chrono::Utc::now(), updated_at: chrono::Utc::now(), status: ModelStatus::Available, size: 1024 * 1024 * 100, // 100MB content_hash: format!("sha256:{}", hex::encode(rand::random::<[u8; 32]>())), dependencies: vec![], schema: rtx_hub::ModelSchema { inputs: vec![rtx_hub::TensorSchema { name: "input".to_string(), dtype: "float32".to_string(), shape: vec![None, Some(768)], description: Some("Model input tensor".to_string()), }], outputs: vec![rtx_hub::TensorSchema { name: "output".to_string(), dtype: "float32".to_string(), shape: vec![None, Some(1000)], description: Some("Model output tensor".to_string()), }], config: Some(json!({ "max_sequence_length": 512, "vocab_size": 30522, "hidden_size": 768 })), }, metrics: HashMap::new(), metadata: HashMap::new(), } }