448 lines
11 KiB
Markdown
448 lines
11 KiB
Markdown
# Settings 配置管理系统
|
||
|
||
## 概述
|
||
|
||
Settings系统是一个灵活的、可扩展的配置管理系统,用于管理网络后台的各种配置项。它使用PostgreSQL数据库存储配置,支持多种数据类型,并提供缓存、验证、历史记录等功能。
|
||
|
||
## 特性
|
||
|
||
- **灵活的数据类型支持**: 支持string、number、boolean、json等类型
|
||
- **分类管理**: 按功能模块分类组织配置项
|
||
- **权限控制**: 区分系统配置和用户配置,支持只读配置
|
||
- **缓存机制**: 内置缓存,提高配置访问性能
|
||
- **历史记录**: 自动记录配置变更历史,支持审计
|
||
- **类型安全**: 提供类型安全的配置访问API
|
||
- **批量操作**: 支持批量更新和导入导出
|
||
- **GraphQL接口**: 完整的GraphQL API支持
|
||
|
||
## 数据库结构
|
||
|
||
### settings表
|
||
|
||
```sql
|
||
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表
|
||
|
||
```sql
|
||
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操作:
|
||
|
||
```rust
|
||
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
|
||
|
||
高级配置管理器,提供缓存和类型安全的访问:
|
||
|
||
```rust
|
||
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
|
||
|
||
配置验证器,确保配置的完整性和正确性:
|
||
|
||
```rust
|
||
use crate::services::settings_manager::SettingsValidator;
|
||
|
||
// 验证必需配置
|
||
let missing = SettingsValidator::validate_required_settings(&manager).await?;
|
||
|
||
// 验证配置类型
|
||
let type_errors = SettingsValidator::validate_setting_types(&manager).await?;
|
||
```
|
||
|
||
## 预定义配置键
|
||
|
||
系统预定义了一些常用的配置键:
|
||
|
||
```rust
|
||
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
|
||
|
||
### 查询
|
||
|
||
```graphql
|
||
# 获取所有配置
|
||
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
|
||
}
|
||
}
|
||
```
|
||
|
||
### 变更
|
||
|
||
```graphql
|
||
# 创建配置
|
||
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")
|
||
}
|
||
```
|
||
|
||
## 使用示例
|
||
|
||
### 基本使用
|
||
|
||
```rust
|
||
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(())
|
||
}
|
||
```
|
||
|
||
### 动态配置更新
|
||
|
||
```rust
|
||
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;
|
||
}
|
||
}
|
||
```
|
||
|
||
### 配置迁移
|
||
|
||
```rust
|
||
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. 性能优化
|
||
|
||
- 合理使用缓存,避免频繁数据库查询
|
||
- 批量操作减少数据库往返
|
||
- 定期清理历史记录表
|
||
|
||
## 扩展性
|
||
|
||
### 添加新的配置类型
|
||
|
||
```rust
|
||
// 在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())
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 添加新的配置分类
|
||
|
||
```rust
|
||
// 在keys模块中添加新的分类常量
|
||
pub mod keys {
|
||
// 现有分类...
|
||
|
||
// 新功能分类
|
||
pub const NEW_FEATURE_ENABLED: &str = "new_feature.enabled";
|
||
pub const NEW_FEATURE_TIMEOUT: &str = "new_feature.timeout";
|
||
}
|
||
```
|
||
|
||
### 自定义验证规则
|
||
|
||
```rust
|
||
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. **权限问题**
|
||
- 确认用户角色
|
||
- 检查配置项是否可编辑
|
||
- 验证系统配置保护
|
||
|
||
### 调试技巧
|
||
|
||
```rust
|
||
// 启用详细日志
|
||
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
|
||
- 配置历史记录和审计
|
||
- 类型安全的配置访问
|
||
- 易于扩展和维护
|
||
|
||
通过合理使用这个系统,可以大大简化应用程序的配置管理,提高系统的可维护性和灵活性。 |