当前位置: 首页 > news >正文

新手教学系列——简单的服务配置项集中管理

前言

在开发和运维过程中,配置管理是一个非常重要但经常被忽视的环节。常用的配置文件格式包括env、ini和yaml等,它们非常适合模块级别的系统配置,尤其是一些敏感信息的配置,例如数据库连接字符串和密码等。但是,对于系统业务级别的配置,通常要求不需要重启服务即可更新,这就是我们今天要介绍的简单配置管理模块的意义所在。

系统配置表

首先,我们需要一个数据库表来存储配置项。这个表包括配置名称、配置值和配置描述等信息。以下是一个使用SQLAlchemy定义的配置表模型:

from sqlalchemy import (TEXT,TIMESTAMP,Column,Integer,String,func,
)from app.models.base import Base, BaseMixinclass SysConfig(Base, BaseMixin):__tablename__ = 'sys_configs'__table_args__ = {"comment": "系统配置表"}id = Column(Integer, primary_key=True, autoincrement=True, comment='ID')cfg_name = Column(String(128), nullable=False, unique=True, comment='配置名称')cfg_value = Column(TEXT, nullable=True, comment='配置值')cfg_desc = Column(String(128), nullable=True, comment='配置描述')updated = Column(TIMESTAMP, index=True, server_default=func.now(), onupdate=func.now(), nullable=False, comment='更新时间')

配置管理类

接下来,我们需要一个配置管理类来加载和更新配置。这个类将会以单例模式运行,确保所有地方使用的配置都是一致的,并且在首次创建实例时自动加载所有配置项。我们使用异步操作来确保数据库操作的高效性。

import json
from typing import Any, Dict, Optional, Type, TypeVar, Callableimport orjson
from app.models.sys_config import SysConfigT = TypeVar('T')# 获取配置管理单例
async def get_config_manager():config_mgr = ConfigManager()if not config_mgr.initialized:await config_mgr.load_configs()return config_mgr# 配置管理类
class ConfigManager:_instance = Nonedef __new__(cls, *args, **kwargs):if cls._instance is None:cls._instance = super(ConfigManager, cls).__new__(cls)return cls._instancedef __init__(self):self.configs: Dict[str, str] = {}self.initialized = Falseasync def load_configs(self):cfg_rows = await SysConfig.get_all_async()for row in cfg_rows:self.configs[row['cfg_name']] = row['cfg_value']self.initialized = Trueprint("Configurations loaded into memory.")async def update_config(self, key: str, value: str, description: str = '', write_to_db=True):self.configs[key] = valueif write_to_db:record = {'cfg_name': key, 'cfg_value': value}if description:record['cfg_desc'] = descriptionawait SysConfig.upsert_async(records=[record], update_keys=['cfg_name'])print(f"Configuration updated: {key} = {value}")def _convert(self, key: str, type_: Type[T], default_value: Optional[T] = None) -> T:value = self.configs.get(key, default_value)if value is None:raise KeyError(f"Configuration key '{key}' not found and no default value provided.")try:if type_ == bool:return type_(value.lower() in ['true', '1', 'yes'])elif type_ == dict or type_ == list:return orjson.loads(value)return type_(value)except (ValueError, TypeError, json.JSONDecodeError) as e:raise ValueError(f"Error converting configuration value '{value}' to type {type_.__name__}: {e}")def __getattr__(self, item: str) -> Callable[[str, Optional[Any]], Any]:supported_types = {'int': int,'float': float,'bool': bool,'str': str,'dict': dict,'list': list,'json': dict,}if item in supported_types:def method(key: str, default_value: Optional[Any] = None) -> Any:return self._convert(key, supported_types[item], default_value)return methodraise AttributeError(f"'ConfigManager' object has no attribute '{item}'")

使用示例

现在,我们已经有了一个完整的配置管理模块,让我们看一下如何在实际应用中使用它。以下是一个示例代码,展示了如何获取配置管理器并使用它来获取和更新配置项。

from app.services import config_servicesasync def main():# 获取配置管理器单例config_mgr = await config_services.get_config_manager()# 更新配置await config_mgr.update_config('max_connections', '100', '最大连接数')await config_mgr.update_config('enable_feature', 'true', '启用新功能')await config_mgr.update_config('custom_dict', '{"key": "value"}', '自定义字典')await config_mgr.update_config('custom_list', '["item1", "item2"]', '自定义列表')# 获取并转换配置值try:max_connections = config_mgr.int('max_connections', 10)print(f"Max Connections: {max_connections}")enable_feature = config_mgr.bool('enable_feature', False)print(f"Enable Feature: {enable_feature}")custom_dict = config_mgr.dict('custom_dict', {})print(f"Custom Dict: {custom_dict}")custom_list = config_mgr.list('custom_list', [])print(f"Custom List: {custom_list}")except (KeyError, ValueError) as e:print(e)# 运行异步主函数
import asyncio
asyncio.run(main())

结语

通过上述代码示例,我们展示了如何创建一个简单而有效的配置管理模块,它能够动态加载和更新配置,支持多种数据类型的转换,并且在设计上注重高效和安全性。这个模块对于需要频繁更改业务逻辑配置而不希望重启服务的应用场景特别有用。

欢迎关注【程序员的开发手册】,我们将继续分享更多实用的开发技巧和工具,让您的开发之路更加顺畅。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • python取色器
  • Pycharm 导入 conda 环境
  • 开发指南047-前端模块版本
  • NineData全面支持PostgreSQL可视化表结构设计
  • 无人机监测的必要性及方法
  • ES证书过期替换方案
  • Python中的数据结构:五彩斑斓的糖果盒
  • 【深度学习入门篇 ⑦】PyTorch池化层
  • python自动化之用flask校验接口token(把token作为参数)
  • Web 安全之 VAPT (漏洞评估与渗透测试)详解
  • GB35114国密算法-GMSSL
  • list的模拟实现
  • 【排序算法】1.冒泡排序-C语言实现
  • C++基础语法:STL之容器(1)--容器概述和序列概述
  • 「Python」基于Gunicorn、Flask和Docker的高并发部署
  • Angular4 模板式表单用法以及验证
  • canvas实际项目操作,包含:线条,圆形,扇形,图片绘制,图片圆角遮罩,矩形,弧形文字...
  • eclipse的离线汉化
  • gf框架之分页模块(五) - 自定义分页
  • JavaScript类型识别
  • JavaScript异步流程控制的前世今生
  • JAVA并发编程--1.基础概念
  • JS题目及答案整理
  • Linux中的硬链接与软链接
  • Python学习笔记 字符串拼接
  • React Native移动开发实战-3-实现页面间的数据传递
  • Spring声明式事务管理之一:五大属性分析
  • Storybook 5.0正式发布:有史以来变化最大的版本\n
  • Stream流与Lambda表达式(三) 静态工厂类Collectors
  • vue中实现单选
  • Webpack 4x 之路 ( 四 )
  • 给github项目添加CI badge
  • 给第三方使用接口的 URL 签名实现
  • 前端面试总结(at, md)
  • 一天一个设计模式之JS实现——适配器模式
  • 用jquery写贪吃蛇
  • 远离DoS攻击 Windows Server 2016发布DNS政策
  • 自动记录MySQL慢查询快照脚本
  • ​软考-高级-系统架构设计师教程(清华第2版)【第15章 面向服务架构设计理论与实践(P527~554)-思维导图】​
  • #LLM入门|Prompt#3.3_存储_Memory
  • #pragma 指令
  • #考研#计算机文化知识1(局域网及网络互联)
  • (16)UiBot:智能化软件机器人(以头歌抓取课程数据为例)
  • (C#)Windows Shell 外壳编程系列9 - QueryInfo 扩展提示
  • (C语言)编写程序将一个4×4的数组进行顺时针旋转90度后输出。
  • (leetcode学习)236. 二叉树的最近公共祖先
  • (webRTC、RecordRTC):navigator.mediaDevices undefined
  • (翻译)Entity Framework技巧系列之七 - Tip 26 – 28
  • (黑马出品_高级篇_01)SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式
  • (算法设计与分析)第一章算法概述-习题
  • (转载)PyTorch代码规范最佳实践和样式指南
  • (转载)利用webkit抓取动态网页和链接
  • .FileZilla的使用和主动模式被动模式介绍
  • .net 7和core版 SignalR
  • .net 获取url的方法