# DI Container Integration Guide **Status**: ✅ Complete **Last Updated**: December 15, 2025 --- ## Overview This guide explains how to use the RiceCoder Dependency Injection (DI) container (`ricecoder-di`) for service registration, resolution, and management. The DI container provides a centralized way to wire services across all RiceCoder crates. ## Table of Contents - [Quick Start](#quick-start) - [Service Registration](#service-registration) - [Service Lifetimes](#service-lifetimes) - [Service Resolution](#service-resolution) - [Feature-Gated Services](#feature-gated-services) - [Conditional Registration](#conditional-registration) - [Health Checks](#health-checks) - [Error Handling](#error-handling) - [Best Practices](#best-practices) - [Examples](#examples) --- ## Quick Start ```rust use ricecoder_di::create_application_container; // Create container with core services let container = create_application_container().unwrap(); // Resolve services let session_manager = container.resolve::().unwrap(); let provider_manager = container.resolve::().unwrap(); ``` ## Service Registration ### Basic Registration Register a service with a factory function: ```rust use ricecoder_di::{DIContainer, register_service}; let container = DIContainer::new(); // Register with closure container.register(|_| { let service = Arc::new(MyService::new()); Ok(service) }).unwrap(); // Or use the macro register_service!(container, MyService, |_| Ok(Arc::new(MyService::new()))); ``` ### Registration with Dependencies Services can depend on other services: ```rust container.register(|container| { let dependency = container.resolve::()?; let service = Arc::new(MyService::new(dependency)); Ok(service) }).unwrap(); ``` ## Service Lifetimes ### Singleton Services Created once and reused throughout the application: ```rust container.register(|_| { Ok(Arc::new(SingletonService::new())) }).unwrap(); ``` ### Transient Services Created each time they're requested: ```rust container.register_transient(|_| { Ok(Arc::new(TransientService::new())) }).unwrap(); ``` ### Scoped Services Created once per scope and reused within that scope: ```rust use ricecoder_di::ServiceScope; container.register_scoped(|_| { Ok(Arc::new(ScopedService::new())) }).unwrap(); let scope = ServiceScope::new(); let service1 = container.resolve_with_scope::(Some(&scope)).unwrap(); let service2 = container.resolve_with_scope::(Some(&scope)).unwrap(); // service1 and service2 are the same instance ``` ## Service Resolution ### Basic Resolution ```rust let service = container.resolve::().unwrap(); ``` ### Resolution with Scope ```rust let scope = ServiceScope::new(); let service = container.resolve_with_scope::(Some(&scope)).unwrap(); ``` ### Checking Service Availability ```rust if container.is_registered::() { let service = container.resolve::().unwrap(); // Use service } ``` ## Feature-Gated Services Services can be conditionally compiled based on Cargo features: ```toml [dependencies] ricecoder-di = { version = "0.1", features = ["storage", "research"] } ``` ### Available Features | Feature | Services Included | |---------|-------------------| | `storage` | StorageManager, FileStorage, MemoryStorage | | `research` | ResearchManager, CodebaseScanner, SemanticIndexer | | `workflows` | WorkflowEngine, WorkflowManager | | `execution` | ExecutionEngine, CommandExecutor | | `mcp` | MCPClient, MCPServer | | `tools` | ToolRegistry, ToolExecutor | | `config` | ConfigManager, ConfigLoader | | `activity-log` | ActivityLogger, AuditLogger, SessionTracker | | `orchestration` | WorkspaceOrchestrator, OperationManager | | `specs` | SpecManager, SpecValidator, SpecCache | | `undo-redo` | UndoManager, RedoManager, HistoryManager | | `vcs` | VCSManager, GitIntegration, RepositoryManager | | `permissions` | PermissionManager, PermissionChecker, AuditLogger | | `security` | AccessControl, EncryptionService, ValidationService | | `cache` | CacheManager, CacheStorage, CacheStrategy | | `domain` | DomainService, Repository, EntityManager | | `learning` | LearningManager, PatternCapturer, RuleValidator | | `industry` | AuthService, ComplianceManager, ConnectionManager | | `safety` | SafetyMonitor, RiskAssessor, ConstraintValidator | | `files` | FileManager, FileWatcher, TransactionManager | | `themes` | ThemeManager, ThemeLoader, ThemeRegistry | | `images` | ImageHandler, ImageAnalyzer, ImageCache | | `completion` | GenericCompletionEngine | | `lsp` | LSP services | | `modes` | ModeManager | | `commands` | CommandManager, CommandRegistry | | `hooks` | HookRegistry | | `keybinds` | KeybindManager | | `teams` | TeamManager | | `refactoring` | ConfigManager, ProviderRegistry | | `full` | All features enabled | ### Using Feature-Gated Services ```rust #[cfg(feature = "storage")] { let storage_manager = container.resolve::().unwrap(); // Use storage services } #[cfg(feature = "research")] { let research_manager = container.resolve::().unwrap(); // Use research services } ``` ## Conditional Registration Register services based on runtime conditions: ```rust // Register based on configuration container.register(|_| { if config.use_file_storage { Ok(Arc::new(FileStorage::new(&config.storage_path))) } else { Ok(Arc::new(MemoryStorage::new())) } }).unwrap(); // Register based on environment container.register(|_| { let provider = if std::env::var("USE_OPENAI").is_ok() { Arc::new(OpenAIProvider::new()) } else { Arc::new(AnthropicProvider::new()) }; Ok(provider) }).unwrap(); ``` ## Health Checks Services can implement health monitoring: ```rust use ricecoder_di::{HealthCheck, HealthStatus}; use async_trait::async_trait; #[async_trait] impl HealthCheck for MyService { async fn health_check(&self) -> DIResult { if self.is_connected() { Ok(HealthStatus::Healthy) } else { Ok(HealthStatus::Unhealthy("Connection lost".to_string())) } } } // Register with health check container.register_with_health_check( |_| Ok(Arc::new(MyService::new())), |service| async move { service.health_check().await } ).unwrap(); // Check all services let health_results = container.health_check_all().unwrap(); for (service_name, status) in health_results { match status { HealthStatus::Healthy => println!("✅ {} is healthy", service_name), HealthStatus::Degraded(reason) => println!("⚠️ {} is degraded: {}", service_name, reason), HealthStatus::Unhealthy(reason) => println!("❌ {} is unhealthy: {}", service_name, reason), } } ``` ## Error Handling Handle common DI errors: ```rust use ricecoder_di::{DIError, DIResult}; match container.resolve::() { Ok(service) => { // Use service } Err(DIError::ServiceNotRegistered { service_type }) => { eprintln!("Service not registered: {}", service_type); // Handle missing service } Err(DIError::DependencyResolutionFailed { message }) => { eprintln!("Dependency resolution failed: {}", message); // Handle dependency issues } Err(DIError::CircularDependency { service_chain }) => { eprintln!("Circular dependency detected: {}", service_chain); // Handle circular dependencies } Err(e) => { eprintln!("DI error: {}", e); // Handle other errors } } ``` ## Best Practices ### 1. Use Appropriate Lifetimes - **Singleton**: Shared resources, expensive objects, stateless services - **Transient**: Lightweight services, per-operation state - **Scoped**: Request-scoped data, user-specific services ### 2. Thread Safety All services must be `Send + Sync`: ```rust struct MyService { data: Arc>, // Use Arc> for shared mutable state } ``` ### 3. Factory Functions Use factory functions for complex initialization: ```rust container.register(|container| { let config = container.resolve::()?; let storage = container.resolve::()?; Ok(Arc::new(MyService::with_dependencies(config, storage))) }).unwrap(); ``` ### 4. Feature Flags Use feature flags for optional functionality: ```rust #[cfg(feature = "advanced_features")] container.register(|_| Ok(Arc::new(AdvancedService::new()))).unwrap(); ``` ### 5. Testing Test services in isolation: ```rust #[test] fn test_service_registration() { let container = DIContainer::new(); container.register(|_| Ok(Arc::new(TestService::new()))).unwrap(); let service = container.resolve::().unwrap(); assert!(service.is_ready()); } ``` ## Examples ### Basic Application Setup ```rust use ricecoder_di::{DIContainerBuilder, DIContainerBuilderExt}; fn setup_container() -> DIResult { let container = DIContainerBuilder::new() .register_infrastructure_services()? .register_use_cases()? .build()?; Ok(container) } ``` ### Advanced Setup with Features ```rust fn setup_full_container() -> DIResult { let mut builder = DIContainerBuilder::new() .register_infrastructure_services()? .register_use_cases()?; // Add optional services based on features #[cfg(feature = "storage")] { builder = builder.register_storage_services()?; } #[cfg(feature = "research")] { builder = builder.register_research_services()?; } #[cfg(feature = "workflows")] { builder = builder.register_workflow_services()?; } let container = builder.build()?; Ok(container) } ``` ### Service with Health Checks ```rust struct DatabaseService { connection_pool: Arc, } #[async_trait] impl HealthCheck for DatabaseService { async fn health_check(&self) -> DIResult { match self.connection_pool.health_check().await { Ok(_) => Ok(HealthStatus::Healthy), Err(e) => Ok(HealthStatus::Unhealthy(e.to_string())), } } } fn register_database_service(container: &DIContainer) -> DIResult<()> { container.register_with_health_check( |_| Ok(Arc::new(DatabaseService::new())), |service| async move { service.health_check().await } ) } ``` --- ## See Also - [Architecture Overview](./Architecture-Overview.md) - System architecture and DI container role - [API Reference](./API-Reference.md) - DI container API documentation - [Service Integration Guide](./Service-Integration-Guide.md) - Adding new services to the DI container --- *Last updated: December 15, 2025*