config_service.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. """
  2. 配置管理服务
  3. 提供统一的系统配置访问接口,支持缓存和热更新
  4. """
  5. import threading
  6. import time
  7. from typing import Any, Optional, Dict
  8. from app.models.system import SystemConfig
  9. from app.database.db_manager import db
  10. import logging
  11. logger = logging.getLogger(__name__)
  12. class ConfigService:
  13. """
  14. 系统配置管理服务
  15. 特性:
  16. - 缓存配置数据,减少数据库查询
  17. - 支持热更新,配置变更时自动刷新缓存
  18. - 类型安全的配置值获取
  19. - 线程安全
  20. """
  21. _instance = None
  22. _lock = threading.Lock()
  23. def __new__(cls):
  24. if cls._instance is None:
  25. with cls._lock:
  26. if cls._instance is None:
  27. cls._instance = super().__new__(cls)
  28. cls._instance._initialized = False
  29. return cls._instance
  30. def __init__(self):
  31. if not self._initialized:
  32. self._config_cache: Dict[str, Any] = {}
  33. self._cache_timestamp = 0
  34. self._cache_ttl = 300 # 缓存5分钟
  35. self._cache_lock = threading.RLock()
  36. self._initialized = True
  37. logger.info("配置服务已初始化")
  38. def _is_cache_valid(self) -> bool:
  39. """检查缓存是否有效"""
  40. return (time.time() - self._cache_timestamp) < self._cache_ttl
  41. def _refresh_cache(self) -> None:
  42. """刷新配置缓存"""
  43. try:
  44. # 检查是否有Flask应用上下文
  45. try:
  46. from flask import has_app_context
  47. if not has_app_context():
  48. logger.warning("没有Flask应用上下文,跳过配置缓存刷新")
  49. return
  50. except ImportError:
  51. logger.warning("Flask未加载,跳过配置缓存刷新")
  52. return
  53. with self._cache_lock:
  54. logger.debug("开始刷新配置缓存...")
  55. # 查询所有活跃的配置
  56. configs = SystemConfig.query.filter_by(is_active=True).all()
  57. # 清空缓存并重新填充
  58. self._config_cache.clear()
  59. for config in configs:
  60. self._config_cache[config.parameter_name] = config.get_typed_value()
  61. self._cache_timestamp = time.time()
  62. logger.info(f"配置缓存已刷新,共加载 {len(self._config_cache)} 个配置参数")
  63. except Exception as e:
  64. logger.error(f"刷新配置缓存失败: {e}")
  65. # 如果刷新失败,保留旧缓存
  66. def get_config(self, parameter_name: str, default_value: Any = None, force_refresh: bool = False) -> Any:
  67. """
  68. 获取配置值
  69. Args:
  70. parameter_name: 参数名称
  71. default_value: 默认值,当配置不存在时返回
  72. force_refresh: 是否强制刷新缓存
  73. Returns:
  74. 配置的实际类型值
  75. """
  76. with self._cache_lock:
  77. # 检查是否需要刷新缓存
  78. if force_refresh or not self._is_cache_valid() or not self._config_cache:
  79. self._refresh_cache()
  80. # 从缓存获取值
  81. if parameter_name in self._config_cache:
  82. value = self._config_cache[parameter_name]
  83. logger.debug(f"从缓存获取配置 {parameter_name} = {value}")
  84. return value
  85. else:
  86. # 缓存中不存在,尝试查询数据库(可能是新添加的配置)
  87. logger.debug(f"缓存中不存在配置 {parameter_name},尝试查询数据库")
  88. # 检查是否有Flask应用上下文
  89. try:
  90. from flask import has_app_context
  91. if not has_app_context():
  92. logger.warning(f"没有Flask应用上下文,无法查询配置 {parameter_name},返回默认值 {default_value}")
  93. return default_value
  94. except ImportError:
  95. logger.warning(f"Flask未加载,无法查询配置 {parameter_name},返回默认值 {default_value}")
  96. return default_value
  97. try:
  98. config = SystemConfig.query.filter_by(
  99. parameter_name=parameter_name,
  100. is_active=True
  101. ).first()
  102. if config:
  103. value = config.get_typed_value()
  104. # 更新缓存
  105. self._config_cache[parameter_name] = value
  106. logger.debug(f"从数据库获取配置 {parameter_name} = {value}")
  107. return value
  108. else:
  109. logger.warning(f"配置参数 {parameter_name} 不存在,返回默认值 {default_value}")
  110. return default_value
  111. except Exception as e:
  112. logger.error(f"查询配置参数 {parameter_name} 失败: {e}")
  113. return default_value
  114. def get_str(self, parameter_name: str, default_value: str = '') -> str:
  115. """获取字符串类型配置"""
  116. value = self.get_config(parameter_name, default_value)
  117. return str(value) if value is not None else default_value
  118. def get_int(self, parameter_name: str, default_value: int = 0) -> int:
  119. """获取整数类型配置"""
  120. value = self.get_config(parameter_name, default_value)
  121. try:
  122. return int(value) if value is not None else default_value
  123. except (ValueError, TypeError):
  124. logger.warning(f"配置 {parameter_name} 无法转换为整数,返回默认值 {default_value}")
  125. return default_value
  126. def get_float(self, parameter_name: str, default_value: float = 0.0) -> float:
  127. """获取浮点数类型配置"""
  128. value = self.get_config(parameter_name, default_value)
  129. try:
  130. return float(value) if value is not None else default_value
  131. except (ValueError, TypeError):
  132. logger.warning(f"配置 {parameter_name} 无法转换为浮点数,返回默认值 {default_value}")
  133. return default_value
  134. def get_bool(self, parameter_name: str, default_value: bool = False) -> bool:
  135. """获取布尔类型配置"""
  136. value = self.get_config(parameter_name, default_value)
  137. if isinstance(value, bool):
  138. return value
  139. elif isinstance(value, str):
  140. return value.upper() in ['TRUE', 'YES', '1', 'ON']
  141. elif isinstance(value, (int, float)):
  142. return bool(value)
  143. else:
  144. return default_value
  145. def get_list(self, parameter_name: str, default_value: list = None) -> list:
  146. """获取列表类型配置"""
  147. if default_value is None:
  148. default_value = []
  149. value = self.get_config(parameter_name, default_value)
  150. return value if isinstance(value, list) else default_value
  151. def set_config(self, parameter_name: str, value: Any) -> bool:
  152. """
  153. 设置配置值
  154. Args:
  155. parameter_name: 参数名称
  156. value: 要设置的值
  157. Returns:
  158. 是否设置成功
  159. """
  160. try:
  161. config = SystemConfig.query.filter_by(parameter_name=parameter_name).first()
  162. if config:
  163. config.set_typed_value(value)
  164. db.session.commit()
  165. # 更新缓存
  166. with self._cache_lock:
  167. self._config_cache[parameter_name] = config.get_typed_value()
  168. logger.info(f"配置参数 {parameter_name} 已更新为: {value}")
  169. return True
  170. else:
  171. logger.error(f"配置参数 {parameter_name} 不存在")
  172. return False
  173. except Exception as e:
  174. logger.error(f"设置配置参数 {parameter_name} 失败: {e}")
  175. db.session.rollback()
  176. return False
  177. def reload_config(self) -> None:
  178. """重新加载所有配置(强制刷新缓存)"""
  179. logger.info("强制重新加载配置缓存")
  180. self._refresh_cache()
  181. def get_config_by_category(self, category: str) -> Dict[str, Any]:
  182. """
  183. 获取指定分类的所有配置
  184. Args:
  185. category: 配置分类
  186. Returns:
  187. 该分类下的所有配置字典
  188. """
  189. try:
  190. configs = SystemConfig.query.filter_by(
  191. category=category,
  192. is_active=True
  193. ).all()
  194. result = {}
  195. for config in configs:
  196. result[config.parameter_name] = config.get_typed_value()
  197. return result
  198. except Exception as e:
  199. logger.error(f"获取分类 {category} 的配置失败: {e}")
  200. return {}
  201. def get_cache_info(self) -> Dict[str, Any]:
  202. """获取缓存状态信息"""
  203. with self._cache_lock:
  204. return {
  205. 'cache_size': len(self._config_cache),
  206. 'cache_timestamp': self._cache_timestamp,
  207. 'cache_age_seconds': time.time() - self._cache_timestamp,
  208. 'cache_ttl_seconds': self._cache_ttl,
  209. 'is_cache_valid': self._is_cache_valid()
  210. }
  211. # 创建全局配置服务实例
  212. config_service = ConfigService()
  213. # 便捷函数,方便在其他模块中使用
  214. def get_config(parameter_name: str, default_value: Any = None) -> Any:
  215. """获取配置值的便捷函数"""
  216. return config_service.get_config(parameter_name, default_value)
  217. def get_str_config(parameter_name: str, default_value: str = '') -> str:
  218. """获取字符串配置的便捷函数"""
  219. return config_service.get_str(parameter_name, default_value)
  220. def get_int_config(parameter_name: str, default_value: int = 0) -> int:
  221. """获取整数配置的便捷函数"""
  222. return config_service.get_int(parameter_name, default_value)
  223. def get_float_config(parameter_name: str, default_value: float = 0.0) -> float:
  224. """获取浮点数配置的便捷函数"""
  225. return config_service.get_float(parameter_name, default_value)
  226. def get_bool_config(parameter_name: str, default_value: bool = False) -> bool:
  227. """获取布尔配置的便捷函数"""
  228. return config_service.get_bool(parameter_name, default_value)
  229. def get_list_config(parameter_name: str, default_value: list = None) -> list:
  230. """获取列表配置的便捷函数"""
  231. return config_service.get_list(parameter_name, default_value or [])
  232. def set_config(parameter_name: str, value: Any) -> bool:
  233. """设置配置值的便捷函数"""
  234. return config_service.set_config(parameter_name, value)
  235. def reload_config() -> None:
  236. """重新加载配置的便捷函数"""
  237. config_service.reload_config()