From 596b2ec7885d740e37882f5099815bb9a31255c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=87=E8=96=87=E5=AE=89?= Date: Sun, 18 Jan 2026 21:16:01 +0800 Subject: [PATCH] a --- backend/config_manager.py | 87 ++++++++++++++++++++++++++++----------- 1 file changed, 62 insertions(+), 25 deletions(-) diff --git a/backend/config_manager.py b/backend/config_manager.py index 649663f..828311c 100644 --- a/backend/config_manager.py +++ b/backend/config_manager.py @@ -5,6 +5,7 @@ import sys import os import json +import re from pathlib import Path from typing import Optional, Any @@ -152,12 +153,8 @@ class ConfigManager: try: # 使用Hash存储所有配置,键为 trading_config:{key} value = self._redis_client.hget('trading_config', key) - if value: - # 尝试解析JSON(如果是复杂类型) - try: - return json.loads(value) - except (json.JSONDecodeError, TypeError): - return value + if value is not None and value != '': + return self._coerce_redis_value(value) except Exception as e: logger.debug(f"从Redis获取配置失败 {key}: {e}") # 连接失败时,尝试重新连接 @@ -168,6 +165,56 @@ class ConfigManager: self._redis_connected = False return None + + @staticmethod + def _coerce_redis_value(value_str: Any) -> Any: + """ + 将 Redis Hash 中的字符串值尽量还原为正确类型。 + + 兼容历史写法: + - 之前 bool 会被写成 "True"/"False"(非 JSON),导致读取后变成字符串,进而在逻辑判断里永远为 True。 + - 现在会优先把 bool/int/float/dict/list 用 JSON 序列化写入(见 _set_to_redis)。 + """ + if value_str is None: + return None + + # redis-py decode_responses=True 时是 str;否则可能是 bytes + if isinstance(value_str, bytes): + try: + value_str = value_str.decode('utf-8', errors='ignore') + except Exception: + value_str = str(value_str) + + s = str(value_str).strip() + if s == '': + return '' + + # 1) JSON 优先(dict/list/bool/number 都能覆盖) + try: + return json.loads(s) + except Exception: + pass + + sl = s.lower() + # 2) bool 兼容(历史 "True"/"False") + if sl in ('true', 'false', '1', '0', 'yes', 'no', 'on', 'off'): + return sl in ('true', '1', 'yes', 'on') + + # 3) number 兼容(避免把 "1h" 之类误判) + # int: -?\d+ + if re.fullmatch(r'-?\d+', s): + try: + return int(s) + except Exception: + return s + # float: -?\d+\.\d+ + if re.fullmatch(r'-?\d+\.\d+', s): + try: + return float(s) + except Exception: + return s + + return s def _set_to_redis(self, key: str, value: Any): """设置配置到Redis""" @@ -176,9 +223,9 @@ class ConfigManager: try: # 使用Hash存储所有配置,键为 trading_config:{key} - # 将值序列化为JSON(如果是复杂类型) - if isinstance(value, (dict, list)): - value_str = json.dumps(value) + # 将值序列化:复杂类型/基础类型使用 JSON,避免 bool 被写成 "False" 字符串后逻辑误判 + if isinstance(value, (dict, list, bool, int, float)): + value_str = json.dumps(value, ensure_ascii=False) else: value_str = str(value) @@ -193,8 +240,8 @@ class ConfigManager: self._redis_client.ping() self._redis_connected = True # 重试一次 - if isinstance(value, (dict, list)): - value_str = json.dumps(value) + if isinstance(value, (dict, list, bool, int, float)): + value_str = json.dumps(value, ensure_ascii=False) else: value_str = str(value) self._redis_client.hset('trading_config', key, value_str) @@ -213,8 +260,8 @@ class ConfigManager: # 批量设置所有配置到Redis pipe = self._redis_client.pipeline() for key, value in self._cache.items(): - if isinstance(value, (dict, list)): - value_str = json.dumps(value) + if isinstance(value, (dict, list, bool, int, float)): + value_str = json.dumps(value, ensure_ascii=False) else: value_str = str(value) pipe.hset('trading_config', key, value_str) @@ -241,13 +288,7 @@ class ConfigManager: if redis_configs and len(redis_configs) > 0: # 解析Redis中的配置 for key, value_str in redis_configs.items(): - try: - # 尝试解析JSON - value = json.loads(value_str) - except (json.JSONDecodeError, TypeError): - # 如果不是JSON,尝试转换类型 - value = value_str - self._cache[key] = value + self._cache[key] = self._coerce_redis_value(value_str) logger.info(f"从Redis加载了 {len(self._cache)} 个配置项") return else: @@ -350,11 +391,7 @@ class ConfigManager: if redis_configs and len(redis_configs) > 0: self._cache = {} # 清空缓存 for key, value_str in redis_configs.items(): - try: - value = json.loads(value_str) - except (json.JSONDecodeError, TypeError): - value = value_str - self._cache[key] = value + self._cache[key] = self._coerce_redis_value(value_str) logger.debug(f"从Redis重新加载了 {len(self._cache)} 个配置项") else: # Redis中没有配置,但不回退到数据库(避免频繁从数据库加载)