mmap/docs/SETTINGS_SYSTEM.md
Tsuki d4448c6129
Some checks are pending
Docker Build and Push / build (push) Waiting to run
sync: add settings
2025-08-11 00:05:52 +08:00

11 KiB
Raw Blame History

Settings 配置管理系统

概述

Settings系统是一个灵活的、可扩展的配置管理系统用于管理网络后台的各种配置项。它使用PostgreSQL数据库存储配置支持多种数据类型并提供缓存、验证、历史记录等功能。

特性

  • 灵活的数据类型支持: 支持string、number、boolean、json等类型
  • 分类管理: 按功能模块分类组织配置项
  • 权限控制: 区分系统配置和用户配置,支持只读配置
  • 缓存机制: 内置缓存,提高配置访问性能
  • 历史记录: 自动记录配置变更历史,支持审计
  • 类型安全: 提供类型安全的配置访问API
  • 批量操作: 支持批量更新和导入导出
  • GraphQL接口: 完整的GraphQL API支持

数据库结构

settings表

CREATE TABLE settings (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    key VARCHAR(255) NOT NULL UNIQUE,
    value TEXT,
    value_type VARCHAR(50) NOT NULL DEFAULT 'string',
    description TEXT,
    category VARCHAR(100) DEFAULT 'general',
    is_encrypted BOOLEAN DEFAULT FALSE,
    is_system BOOLEAN DEFAULT FALSE,
    is_editable BOOLEAN DEFAULT TRUE,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    created_by UUID,
    updated_by UUID
);

settings_history表

CREATE TABLE settings_history (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    setting_id UUID NOT NULL REFERENCES settings(id) ON DELETE CASCADE,
    old_value TEXT,
    new_value TEXT,
    changed_by UUID,
    change_reason TEXT,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);

核心组件

1. SettingsService

基础的配置服务提供CRUD操作

use crate::services::settings_service::SettingsService;

let settings_service = SettingsService::new(pool);

// 创建配置
let setting = settings_service.create_setting(create_setting, user_id).await?;

// 获取配置
let setting = settings_service.get_setting_by_key("app.name").await?;

// 更新配置
let updated = settings_service.update_setting(id, update_setting, user_id).await?;

// 删除配置
let deleted = settings_service.delete_setting(id).await?;

2. SettingsManager

高级配置管理器,提供缓存和类型安全的访问:

use crate::services::settings_manager::{SettingsManager, keys};

let settings_manager = SettingsManager::new(settings_service);

// 类型安全的配置访问
let app_name = settings_manager.get_string_or(keys::APP_NAME, "Default App").await?;
let max_connections = settings_manager.get_int_or(keys::DB_MAX_CONNECTIONS, 10).await?;
let debug_mode = settings_manager.get_bool_or(keys::APP_DEBUG, false).await?;

// 动态更新配置
settings_manager.set_value(keys::DB_MAX_CONNECTIONS, &20).await?;

// 批量更新
let mut updates = HashMap::new();
updates.insert(keys::KAFKA_MAX_RETRIES.to_string(), Value::Number(5));
settings_manager.set_values(updates).await?;

3. SettingsValidator

配置验证器,确保配置的完整性和正确性:

use crate::services::settings_manager::SettingsValidator;

// 验证必需配置
let missing = SettingsValidator::validate_required_settings(&manager).await?;

// 验证配置类型
let type_errors = SettingsValidator::validate_setting_types(&manager).await?;

预定义配置键

系统预定义了一些常用的配置键:

pub mod keys {
    // 应用配置
    pub const APP_NAME: &str = "app.name";
    pub const APP_VERSION: &str = "app.version";
    pub const APP_DEBUG: &str = "app.debug";
    pub const APP_TIMEZONE: &str = "app.timezone";
    
    // 数据库配置
    pub const DB_MAX_CONNECTIONS: &str = "database.max_connections";
    pub const DB_CONNECTION_TIMEOUT: &str = "database.connection_timeout";
    
    // Kafka配置
    pub const KAFKA_MAX_RETRIES: &str = "kafka.max_retries";
    pub const KAFKA_RETRY_DELAY: &str = "kafka.retry_delay";
    
    // 安全配置
    pub const SECURITY_SESSION_TIMEOUT: &str = "security.session_timeout";
    pub const SECURITY_MAX_LOGIN_ATTEMPTS: &str = "security.max_login_attempts";
    
    // 日志配置
    pub const LOGGING_LEVEL: &str = "logging.level";
    pub const LOGGING_MAX_FILES: &str = "logging.max_files";
    
    // 缓存配置
    pub const CACHE_TTL: &str = "cache.ttl";
    pub const CACHE_MAX_SIZE: &str = "cache.max_size";
}

GraphQL API

查询

# 获取所有配置
query {
  settings {
    id
    key
    value
    valueType
    description
    category
    isSystem
    isEditable
    createdAt
    updatedAt
  }
}

# 按分类过滤配置
query {
  settings(filter: { category: "app" }) {
    key
    value
    description
  }
}

# 获取配置统计
query {
  settingsStats {
    categories
    stats
  }
}

# 获取配置历史
query {
  settingHistory(settingId: "uuid") {
    oldValue
    newValue
    changedBy
    createdAt
  }
}

变更

# 创建配置
mutation {
  createSetting(input: {
    key: "custom.setting"
    value: "custom_value"
    valueType: "string"
    description: "Custom setting"
    category: "custom"
  }) {
    id
    key
    value
  }
}

# 更新配置
mutation {
  updateSetting(
    id: "uuid"
    input: { value: "new_value" }
  ) {
    key
    value
    updatedAt
  }
}

# 批量更新
mutation {
  batchUpdateSettings(input: {
    updates: [
      { key: "app.name", value: "New App Name" }
      { key: "app.debug", value: true }
    ]
  }) {
    key
    value
  }
}

# 删除配置
mutation {
  deleteSetting(id: "uuid")
}

使用示例

基本使用

use crate::services::settings_manager::{SettingsManager, keys};

async fn configure_app(settings_manager: &SettingsManager) -> Result<(), Box<dyn std::error::Error>> {
    // 获取应用配置
    let app_name = settings_manager.get_string_or(keys::APP_NAME, "Default App").await?;
    let debug_mode = settings_manager.get_bool_or(keys::APP_DEBUG, false).await?;
    
    // 根据配置调整应用行为
    if debug_mode {
        println!("调试模式已启用");
        // 设置更详细的日志级别
    }
    
    println!("应用名称: {}", app_name);
    Ok(())
}

动态配置更新

async fn dynamic_config_update(settings_manager: &SettingsManager) -> Result<(), Box<dyn std::error::Error>> {
    // 监听配置变化
    loop {
        let max_connections = settings_manager.get_int_or(keys::DB_MAX_CONNECTIONS, 10).await?;
        let connection_timeout = settings_manager.get_int_or(keys::DB_CONNECTION_TIMEOUT, 30).await?;
        
        // 根据配置调整数据库连接池
        adjust_database_pool(max_connections, connection_timeout).await?;
        
        // 等待一段时间后再次检查
        tokio::time::sleep(tokio::time::Duration::from_secs(60)).await;
    }
}

配置迁移

async fn migrate_old_configs(settings_service: &SettingsService) -> Result<(), Box<dyn std::error::Error>> {
    let old_configs = vec![
        ("old.setting.1", "value1", "string"),
        ("old.setting.2", "100", "number"),
    ];
    
    for (key, value, value_type) in old_configs {
        let create_setting = CreateSetting {
            key: key.to_string(),
            value: Some(value.to_string()),
            value_type: value_type.to_string(),
            description: Some("Migrated from old system".to_string()),
            category: "migrated".to_string(),
            is_encrypted: Some(false),
            is_system: Some(false),
            is_editable: Some(true),
        };
        
        settings_service.create_setting(create_setting, uuid::Uuid::nil()).await?;
    }
    
    Ok(())
}

最佳实践

1. 配置命名规范

  • 使用点分隔的层次结构:module.submodule.setting_name
  • 使用小写字母和下划线
  • 保持命名的一致性和可读性

2. 配置分类

  • 按功能模块分类:appdatabasekafkasecurity
  • 使用general分类存放通用配置
  • 为自定义配置使用专门的分类名

3. 配置类型选择

  • string: 文本配置,如应用名称、文件路径等
  • number: 数值配置,如超时时间、连接数等
  • boolean: 开关配置,如调试模式、功能开关等
  • json: 复杂配置如API配置、映射关系等

4. 安全考虑

  • 敏感配置设置is_encrypted = true
  • 系统关键配置设置is_system = true
  • 只读配置设置is_editable = false

5. 性能优化

  • 合理使用缓存,避免频繁数据库查询
  • 批量操作减少数据库往返
  • 定期清理历史记录表

扩展性

添加新的配置类型

// 在Settings模型中添加新的类型支持
impl Setting {
    pub fn get_custom_type(&self) -> Result<CustomType, String> {
        if self.value_type == "custom" {
            // 自定义类型解析逻辑
            CustomType::from_str(&self.value.unwrap_or_default())
                .map_err(|e| e.to_string())
        } else {
            Err("Setting is not a custom type".to_string())
        }
    }
}

添加新的配置分类

// 在keys模块中添加新的分类常量
pub mod keys {
    // 现有分类...
    
    // 新功能分类
    pub const NEW_FEATURE_ENABLED: &str = "new_feature.enabled";
    pub const NEW_FEATURE_TIMEOUT: &str = "new_feature.timeout";
}

自定义验证规则

impl SettingsValidator {
    pub async fn validate_custom_rules(manager: &SettingsManager) -> Result<Vec<String>> {
        let mut errors = Vec::new();
        
        // 自定义验证逻辑
        let feature_enabled = manager.get_bool_or(keys::NEW_FEATURE_ENABLED, false).await?;
        let feature_timeout = manager.get_int_or(keys::NEW_FEATURE_TIMEOUT, 30).await?;
        
        if feature_enabled && feature_timeout < 10 {
            errors.push("Feature timeout must be at least 10 seconds when enabled".to_string());
        }
        
        Ok(errors)
    }
}

故障排除

常见问题

  1. 配置不生效

    • 检查缓存是否过期
    • 验证配置项是否存在
    • 确认配置项类型是否正确
  2. 性能问题

    • 检查缓存设置
    • 优化数据库查询
    • 减少不必要的配置访问
  3. 权限问题

    • 确认用户角色
    • 检查配置项是否可编辑
    • 验证系统配置保护

调试技巧

// 启用详细日志
if settings_manager.get_bool_or(keys::APP_DEBUG, false).await? {
    println!("当前配置状态:");
    let all_settings = settings_manager.get_all_settings().await?;
    for setting in all_settings {
        println!("  {}: {} ({})", setting.key, setting.value.unwrap_or_default(), setting.value_type);
    }
}

// 强制刷新缓存
settings_manager.force_refresh_cache().await?;

总结

Settings系统提供了一个强大而灵活的配置管理解决方案支持

  • 多种数据类型的配置存储
  • 分类管理和权限控制
  • 缓存和性能优化
  • 完整的GraphQL API
  • 配置历史记录和审计
  • 类型安全的配置访问
  • 易于扩展和维护

通过合理使用这个系统,可以大大简化应用程序的配置管理,提高系统的可维护性和灵活性。