Skip to content

Task 000: Centralized Configuration Module #7533

@slin1237

Description

@slin1237

Task 000: Centralized Configuration Module

Summary

Create a comprehensive configuration module that centralizes all validation logic, provides type-safe configuration structures, and eliminates scattered validation code throughout the router.

Problem Statement

Currently, configuration validation is scattered across multiple locations:

  • URL validation happens in Python code
  • Mode compatibility checks occur during server startup
  • Policy parameter validation is embedded in individual routers
  • No centralized error handling for configuration issues
  • Duplicate validation logic in different components

This leads to:

  • Inconsistent validation rules
  • Runtime errors that could be caught at startup
  • Difficult maintenance when adding new configuration options
  • Poor error messages that don't guide users to fixes

Proposed Solution

1. Configuration Type System

Create strongly-typed configuration structures with built-in validation:

// src/config/types.rs
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RouterConfig {
    pub mode: RoutingMode,
    pub policy: PolicyConfig,
    pub host: String,
    pub port: u16,
    pub workers: Vec<String>,
    pub service_discovery: Option<DiscoveryConfig>,
    pub metrics: MetricsConfig,
    pub timeouts: TimeoutConfig,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum RoutingMode {
    Regular,
    PrefillDecode {
        prefill_urls: Vec<(String, Option<u16>)>,
        decode_urls: Vec<String>,
    },
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum PolicyConfig {
    Random,
    RoundRobin,
    CacheAware {
        cache_threshold: f32,
        balance_abs_threshold: usize,
        balance_rel_threshold: f32,
        eviction_period_hours: u64,
    },
    PowerOfTwo {
        interval_secs: u64,
    },
}

2. Validation Framework

// src/config/validation.rs
pub struct ConfigValidator;

impl ConfigValidator {
    pub fn validate(config: &RouterConfig) -> Result<(), ConfigError> {
        self.validate_basic_fields(config)?;
        self.validate_urls(config)?;
        self.validate_mode_policy_compatibility(config)?;
        self.validate_worker_requirements(config)?;
        self.validate_numeric_ranges(config)?;
        Ok(())
    }
    
    fn validate_urls(&self, config: &RouterConfig) -> Result<(), ConfigError> {
        for url in &config.workers {
            let parsed = Url::parse(url).map_err(|e| 
                ConfigError::InvalidValue {
                    field: "workers".to_string(),
                    value: url.clone(),
                    reason: format!("Invalid URL format: {}", e),
                }
            )?;
            
            if parsed.scheme() != "http" && parsed.scheme() != "https" {
                return Err(ConfigError::InvalidValue {
                    field: "workers".to_string(),
                    value: url.clone(),
                    reason: "URL must use http or https scheme".to_string(),
                });
            }
        }
        Ok(())
    }
}

3. Error Types

// src/config/error.rs
#[derive(Debug, thiserror::Error)]
pub enum ConfigError {
    #[error("Validation failed: {0}")]
    ValidationFailed(String),
    
    #[error("Invalid value for field '{field}': {value} - {reason}")]
    InvalidValue {
        field: String,
        value: String,
        reason: String,
    },
    
    #[error("Incompatible configuration: {0}")]
    IncompatibleConfig(String),
    
    #[error("Missing required field: {0}")]
    MissingRequired(String),
}

4. Configuration Builder

// src/config/builder.rs
pub struct ConfigBuilder {
    config: RouterConfig,
}

impl ConfigBuilder {
    pub fn new() -> Self {
        Self {
            config: RouterConfig::default(),
        }
    }
    
    pub fn mode(mut self, mode: RoutingMode) -> Self {
        self.config.mode = mode;
        self
    }
    
    pub fn policy(mut self, policy: PolicyConfig) -> Self {
        self.config.policy = policy;
        self
    }
    
    pub fn validate_and_build(self) -> Result<RouterConfig, ConfigError> {
        ConfigValidator::validate(&self.config)?;
        Ok(self.config)
    }
}

Implementation Plan

Step 1: Create Config Module Structure

  • Create src/config/mod.rs to define module structure
  • Create submodules: types.rs, validation.rs, error.rs
  • Set up module exports and visibility

Step 2: Define Configuration Types

  • Implement all configuration structs and enums
  • Add serde derives for future config file support
  • Implement Default traits with sensible defaults

Step 3: Implement Validation Logic

  • Create ConfigValidator with comprehensive validation methods
  • Add field-level validation (URLs, ports, ranges)
  • Add cross-field validation (mode/policy compatibility)
  • Implement clear error messages with actionable fixes

Step 4: Migration Integration

  • Create conversion methods from old config to new
  • Add backward compatibility layer during transition
  • Update router initialization to use new config

Step 5: Testing Suite

  • Unit tests for each validation rule
  • Integration tests for full config validation
  • Error message quality tests
  • Performance benchmarks for validation

Benefits

  1. Early Error Detection: Configuration errors caught at startup
  2. Better Error Messages: Clear, actionable error descriptions
  3. Type Safety: Compile-time guarantees for configuration structure
  4. Centralized Logic: All validation in one place
  5. Extensibility: Easy to add new configuration options
  6. Documentation: Types serve as documentation
  7. Future-Ready: Foundation for config files and hot reload

Migration Strategy

  1. Implement new config module alongside existing code
  2. Add adapter layer to convert from old format
  3. Gradually migrate components to use new config
  4. Remove old validation code once fully migrated
  5. Enable config file loading as final step

Acceptance Criteria

  • All configuration types defined with proper structure
  • Comprehensive validation for all fields
  • Clear error messages for all failure cases
  • No scattered validation code remains
  • Configuration can be built programmatically
  • Documentation with examples

Estimated Effort

  • Implementation: 2 days
  • Testing: 2 days
  • Migration and integration: 1 day
  • Total: 5 days

Dependencies

None - this is a foundational task that other improvements will build upon

Risks and Mitigations

  1. Risk: Breaking changes to existing API

    • Mitigation: Maintain backward compatibility during transition
    • Mitigation: Provide clear migration guide
  2. Risk: Over-engineering configuration

    • Mitigation: Start with current needs, design for extension
    • Mitigation: Regular design reviews
  3. Risk: Performance impact from validation

    • Mitigation: Run validation only at startup
    • Mitigation: Optimize hot paths if needed

Future Enhancements

  1. Configuration Files: Load from YAML/TOML
  2. Hot Reload: Update config without restart
  3. Validation Profiles: Different rules for dev/prod
  4. Config Schema Export: Generate documentation
  5. Environment Variable Support: Override from env

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions