11 KiB
11 KiB
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. 配置分类
- 按功能模块分类:
app、database、kafka、security等 - 使用
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)
}
}
故障排除
常见问题
-
配置不生效
- 检查缓存是否过期
- 验证配置项是否存在
- 确认配置项类型是否正确
-
性能问题
- 检查缓存设置
- 优化数据库查询
- 减少不必要的配置访问
-
权限问题
- 确认用户角色
- 检查配置项是否可编辑
- 验证系统配置保护
调试技巧
// 启用详细日志
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
- 配置历史记录和审计
- 类型安全的配置访问
- 易于扩展和维护
通过合理使用这个系统,可以大大简化应用程序的配置管理,提高系统的可维护性和灵活性。