This commit is contained in:
薇薇安 2026-01-18 21:16:01 +08:00
parent 31486b5026
commit 596b2ec788

View File

@ -5,6 +5,7 @@
import sys import sys
import os import os
import json import json
import re
from pathlib import Path from pathlib import Path
from typing import Optional, Any from typing import Optional, Any
@ -152,12 +153,8 @@ class ConfigManager:
try: try:
# 使用Hash存储所有配置键为 trading_config:{key} # 使用Hash存储所有配置键为 trading_config:{key}
value = self._redis_client.hget('trading_config', key) value = self._redis_client.hget('trading_config', key)
if value: if value is not None and value != '':
# 尝试解析JSON如果是复杂类型 return self._coerce_redis_value(value)
try:
return json.loads(value)
except (json.JSONDecodeError, TypeError):
return value
except Exception as e: except Exception as e:
logger.debug(f"从Redis获取配置失败 {key}: {e}") logger.debug(f"从Redis获取配置失败 {key}: {e}")
# 连接失败时,尝试重新连接 # 连接失败时,尝试重新连接
@ -169,6 +166,56 @@ class ConfigManager:
return None 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): def _set_to_redis(self, key: str, value: Any):
"""设置配置到Redis""" """设置配置到Redis"""
if not self._redis_connected or not self._redis_client: if not self._redis_connected or not self._redis_client:
@ -176,9 +223,9 @@ class ConfigManager:
try: try:
# 使用Hash存储所有配置键为 trading_config:{key} # 使用Hash存储所有配置键为 trading_config:{key}
# 将值序列化为JSON如果是复杂类型 # 将值序列化:复杂类型/基础类型使用 JSON避免 bool 被写成 "False" 字符串后逻辑误判
if isinstance(value, (dict, list)): if isinstance(value, (dict, list, bool, int, float)):
value_str = json.dumps(value) value_str = json.dumps(value, ensure_ascii=False)
else: else:
value_str = str(value) value_str = str(value)
@ -193,8 +240,8 @@ class ConfigManager:
self._redis_client.ping() self._redis_client.ping()
self._redis_connected = True self._redis_connected = True
# 重试一次 # 重试一次
if isinstance(value, (dict, list)): if isinstance(value, (dict, list, bool, int, float)):
value_str = json.dumps(value) value_str = json.dumps(value, ensure_ascii=False)
else: else:
value_str = str(value) value_str = str(value)
self._redis_client.hset('trading_config', key, value_str) self._redis_client.hset('trading_config', key, value_str)
@ -213,8 +260,8 @@ class ConfigManager:
# 批量设置所有配置到Redis # 批量设置所有配置到Redis
pipe = self._redis_client.pipeline() pipe = self._redis_client.pipeline()
for key, value in self._cache.items(): for key, value in self._cache.items():
if isinstance(value, (dict, list)): if isinstance(value, (dict, list, bool, int, float)):
value_str = json.dumps(value) value_str = json.dumps(value, ensure_ascii=False)
else: else:
value_str = str(value) value_str = str(value)
pipe.hset('trading_config', key, value_str) pipe.hset('trading_config', key, value_str)
@ -241,13 +288,7 @@ class ConfigManager:
if redis_configs and len(redis_configs) > 0: if redis_configs and len(redis_configs) > 0:
# 解析Redis中的配置 # 解析Redis中的配置
for key, value_str in redis_configs.items(): for key, value_str in redis_configs.items():
try: self._cache[key] = self._coerce_redis_value(value_str)
# 尝试解析JSON
value = json.loads(value_str)
except (json.JSONDecodeError, TypeError):
# 如果不是JSON尝试转换类型
value = value_str
self._cache[key] = value
logger.info(f"从Redis加载了 {len(self._cache)} 个配置项") logger.info(f"从Redis加载了 {len(self._cache)} 个配置项")
return return
else: else:
@ -350,11 +391,7 @@ class ConfigManager:
if redis_configs and len(redis_configs) > 0: if redis_configs and len(redis_configs) > 0:
self._cache = {} # 清空缓存 self._cache = {} # 清空缓存
for key, value_str in redis_configs.items(): for key, value_str in redis_configs.items():
try: self._cache[key] = self._coerce_redis_value(value_str)
value = json.loads(value_str)
except (json.JSONDecodeError, TypeError):
value = value_str
self._cache[key] = value
logger.debug(f"从Redis重新加载了 {len(self._cache)} 个配置项") logger.debug(f"从Redis重新加载了 {len(self._cache)} 个配置项")
else: else:
# Redis中没有配置但不回退到数据库避免频繁从数据库加载 # Redis中没有配置但不回退到数据库避免频繁从数据库加载