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

前言

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

系统配置表

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

from sqlalchemy import (
    TEXT,
    TIMESTAMP,
    Column,
    Integer,
    String,
    func,
)

from app.models.base import Base, BaseMixin

class 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, Callable

import orjson
from app.models.sys_config import SysConfig

T = 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 = None

    def __new__(cls, *args, **kwargs):
        if cls._instance is None:
            cls._instance = super(ConfigManager, cls).__new__(cls)
        return cls._instance

    def __init__(self):
        self.configs: Dict[str, str] = {}
        self.initialized = False

    async 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 = True
        print("Configurations loaded into memory.")

    async def update_config(self, key: str, value: str, description: str = '', write_to_db=True):
        self.configs[key] = value
        if write_to_db:
            record = {'cfg_name': key, 'cfg_value': value}
            if description:
                record['cfg_desc'] = description
            await 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 method
        raise AttributeError(f"'ConfigManager' object has no attribute '{item}'")

使用示例

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

from app.services import config_services

async 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())

结语

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/803285.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【文心智能体】前几天百度热搜有一条非常有趣的话题《00后疯感工牌》,看看如何通过低代码工作流方式实现图片显示

00后疯感工牌体验:https://mbd.baidu.com/ma/s/6yA90qtM 目录 前言比赛推荐工作流创建工作流入口创建工作流界面工作流界面HTTP工具卡点地方 总结推荐文章 前言 前几天百度热搜有一条非常有有趣《00后疯感工牌》。 想着通过文心智能体去一键生成00后疯感工牌是不是…

大语言模型在病理AI领域的应用·1|24-07-17·文献速递

小罗碎碎念 今日文献主题:大语言模型技术在病理组学中的应用 这次从厦门开会回来以后,一直在思考大语言模型在病理AI中的一个应用场景,为了辅助自己得出一个科学的结论,我搜集了最新发表的30篇与之相关的文献,用6期推文…

【解决】多个网卡导致nacos注册的服务ip有误问题

解决办法 在本地idea中启动的时候添加启动配置: 方法一 -Dspring.cloud.inetutils.preferred-networks你自己网卡的ip 方法二 -Dspring.cloud.nacos.discovery.ip你自己网卡的ip

封装网络请求 鸿蒙APP HarmonyOS ArkTS

一、效果展示 通过在页面直接调用 userLogin(params) 方法,获取登录令牌 二、申请网络权限 访问网络时候首先需要申请网络权限,需要修改 src/main 目录下的 module.json5 文件,加入 requestPermissions 属性,详见官方文档 【声明权…

陪玩系统小程序模式APP小程序H5系统搭建开发

随着移动互联网的营及和游戏行业的蓬轨发展,陪玩服务应远而生并迅速唱起,陪玩系统小程序作为连接游戏玩家与陪玩师的桥梁,其模式系统的搭建与开发是得尤为重要,本文将洋细凰述陪玩系统小程宗模式系统的搭建开发流程,包…

PCIe驱动开发(3)— 驱动设备文件的创建与操作

PCIe驱动开发(3)— 驱动设备文件的创建与操作 一、前言 在 Linux 中一切皆为文件,驱动加载成功以后会在“/dev”目录下生成一个相应的文件,应用程序通过对这个名为“/dev/xxx” (xxx 是具体的驱动文件名字)的文件进行相应的操作即…

C语言------指针讲解(2)

目录 一、数组名的理解 二、使用指针访问数组 三、一维数组传参的本质 四、冒泡排序 五、二级指针 六、指针数组 七、指针数组模拟二维数组 一、数组名的理解 通过学习,我们知道:数组名和数组首元素的地址打印出来的结果一模一样,数组…

信息安全CISSP认证重点学什么?学习后能掌握哪些安全技能?

引言: 想要在信息安全领域取得突破?那么CISSP认证是您必不可少的一步!本文将为您介绍CISSP认证的重点学习内容以及学习后可以掌握的安全技能,助您更好地了解并准备这一全球认可的信息安全证书。 随着信息安全领域的不断发展&…

【教学类-67-02】20240716毛毛虫ABB排序

背景需求: 【教学类-67-01】20240715毛毛虫AB排序-CSDN博客文章浏览阅读584次,点赞16次,收藏6次。【教学类-67-01】20240715毛毛虫AB排序https://blog.csdn.net/reasonsummer/article/details/140443310 在AB排序基础上,继续制作…

2024年带你轻松掌握最火10款项目管理软件:解决企业项目管理难题的利器

本文向您推荐10款卓越非凡的项目管理软件!它们能有效地助您梳理思绪,极大提高工作效率,使您即使身处繁忙之中仍能保持井然有序。这十款工具各具特色,从简洁明了的任务清单到复杂精密的项目追踪需求,满足各类用户群体的…

Python中的数据结构:五彩斑斓的糖果盒

在Python编程的世界里,数据结构就像是一个个五彩斑斓的糖果盒,每一种糖果都有其独特的味道和形状。这些多姿多彩,形状和味道各异的糖果盒子包括了:List(列表)、Tuple(元组)、Diction…

【Java开发实训】day05——数组常见算法

目录 一、数组翻转 1.1示例代码 1.2适用场景 二、冒泡排序 2.1示例代码 2.2适用场景 三、二分查找 3.1示例代码 3.2适用场景 🌈嗨!我是Filotimo__🌈。很高兴与大家相识,希望我的博客能对你有所帮助。 💡本文由Filotimo…

【软件建模与设计】-04-软件设计和体系结构概念

目录 1、类与对象 2、信息隐藏 2.1、示例 3、继承和泛化/特化 4、并发处理 4.1、并发对象间的协作 5、设计模式 6、软件体系结构和构件 7、软件质量属性 1、类与对象 一个对象是现实世界中物理的或概念的实体。 一个对象盖了数据(data)以及作用于数据之上的过程(pro…

Sentinel规则持久化Push模式两种实现方式

文章目录 sentinel持久化push推模式微服务端的实现具体实现源码分析读数据源写数据源的实现 微服务端解析读数据源流程 修改源码的实现官方demo修改源码实现配置类flowauthoritydegreadparamsystemgateway修改源码 测试补充 前置知识 pull模式 sentinel持久化push推模式 pull拉…

liunx面试题目

如何看当前Linux系统有几颗物理CPU和每颗CPU的核数? 查看物理cup: cat /proc/cpuinfo|grep -c ‘physical id’ 查看每颗cup核数 cat /proc/cpuinfo|grep -c ‘processor’ 若希望自动实现软件包的更新,可以使用yum-cron并启动该服务 yum -y …

解决一下git clone失败的问题

1).不开梯子,我们用https克隆 git clone https://github.com 报错: Failed to connect to github.com port 443 after 2091 ms: Couldnt connect to server 解决办法: 开梯子,然后# 注意修改成自己的IP和端口号 gi…

[HDCTF2019]MFC

[HDCTF2019]MFC-CSDN博客 不会写 完全画瓢 我还以为win32什么系统逆向 原来是小瘪三! VM保护 下载xspy(看雪上有) 打开32位的 再打开 这个窗口 把这个放大镜托到这个大窗口(里面有个小窗口,不要托错了) 下面这个 onmeg 就她不正常,是什么0464 #include <stdio.h&g…

简易ELK搭建

ELK搭建 1. elasticsearch1.1 下载1.2 ES配置1.3 启动ES1.4 开启权限认证1.5 IK分词器配置&#xff08;非必须&#xff09; 2. kibana2.1 下载2.2 配置2.3 启动kibana 3. logstash3.1 下载3.2 配置3.3 启动logstash 4. springboot推送数据 ELK包括elasticsearch、logstash、kib…

自然语言处理(NLP)——法国工程师IMT联盟 期末考试题

1. 问题1 &#xff08;法语&#xff09;En langue arabe lcrasante majorit des mots sont forms par des combinaisons de racines et de schmes. Dans ce mcanisme... &#xff08;英语&#xff09;In Arabic language the vast majority&#xff08;十之八九&#xff09; of…

《昇思25天学习打卡营第23天|onereal》

第23天学习内容简介&#xff1a; ----------------------------------------------------------------------------- 本案例基于MindNLP和ChatGLM-6B实现一个聊天应用。 1 环境配置 配置网络线路 2 代码开发 下载权重大约需要10分钟 ------------------------------- 运…