fix: 修复odbc初始化失败程序无法启动。

hsyh
NoahLan 4 months ago
parent d7310c7fbd
commit 71e8ccf69c

@ -28,6 +28,20 @@ __all__ = [
] ]
def init_erp(app) -> None: def init_erp(app) -> None:
# 初始化ERP管理器 """初始化ERP管理器ODBC和API"""
erp_odbc.init_app(app) import logging
erp_api.init_app(app) logger = logging.getLogger(__name__)
# 初始化ODBC管理器失败不中断启动
try:
erp_odbc.init_app(app)
except Exception as e:
logger.error(f"ERP ODBC管理器初始化失败: {e}", exc_info=True)
logger.warning("应用将继续启动但ODBC功能将不可用")
# 初始化API管理器失败不中断启动
try:
erp_api.init_app(app)
except Exception as e:
logger.error(f"ERP API管理器初始化失败: {e}", exc_info=True)
logger.warning("应用将继续启动但API功能将不可用")

@ -19,7 +19,7 @@ class PyODBCConnectionPool:
"""纯pyodbc连接池实现""" """纯pyodbc连接池实现"""
def __init__(self, dsn: str, pool_size: int = 5, max_overflow: int = 10, def __init__(self, dsn: str, pool_size: int = 5, max_overflow: int = 10,
pool_timeout: int = 30, pool_recycle: int = 3600): pool_timeout: int = 30, pool_recycle: int = 3600, lazy_init: bool = False):
""" """
初始化连接池 初始化连接池
@ -29,12 +29,14 @@ class PyODBCConnectionPool:
max_overflow: 最大溢出连接数 max_overflow: 最大溢出连接数
pool_timeout: 获取连接超时 pool_timeout: 获取连接超时
pool_recycle: 连接回收时间 pool_recycle: 连接回收时间
lazy_init: 是否延迟初始化不预创建连接
""" """
self.dsn = dsn self.dsn = dsn
self.pool_size = pool_size self.pool_size = pool_size
self.max_overflow = max_overflow self.max_overflow = max_overflow
self.pool_timeout = pool_timeout self.pool_timeout = pool_timeout
self.pool_recycle = pool_recycle self.pool_recycle = pool_recycle
self._is_available = False
# 连接池队列 # 连接池队列
self._pool = Queue(maxsize=pool_size) self._pool = Queue(maxsize=pool_size)
@ -42,12 +44,19 @@ class PyODBCConnectionPool:
self._overflow_count = 0 self._overflow_count = 0
self._overflow_lock = Lock() self._overflow_lock = Lock()
# 预创建连接 # 预创建连接(如果不是延迟初始化)
for _ in range(pool_size): if not lazy_init:
conn = self._create_connection() try:
self._pool.put((conn, time.time())) for _ in range(pool_size):
conn = self._create_connection()
logger.info(f"ODBC连接池初始化成功: DSN={dsn}, 池大小={pool_size}") self._pool.put((conn, time.time()))
self._is_available = True
logger.info(f"ODBC连接池初始化成功: DSN={dsn}, 池大小={pool_size}")
except Exception as e:
logger.error(f"ODBC连接池初始化失败: {e}")
self._is_available = False
else:
logger.info(f"ODBC连接池延迟初始化: DSN={dsn}, 池大小={pool_size}")
def _create_connection(self): def _create_connection(self):
"""创建新连接""" """创建新连接"""
@ -75,9 +84,29 @@ class PyODBCConnectionPool:
except: except:
return False return False
def is_available(self) -> bool:
"""检查连接池是否可用"""
return self._is_available
def test_connection(self) -> bool:
"""测试连接是否可用"""
try:
conn = self._create_connection()
conn.close()
self._is_available = True
return True
except Exception as e:
logger.error(f"ODBC连接测试失败: {e}")
self._is_available = False
return False
@contextmanager @contextmanager
def get_connection(self): def get_connection(self):
"""获取连接(上下文管理器)""" """获取连接(上下文管理器)"""
# 检查连接池是否可用
if not self._is_available:
raise Exception("ODBC连接池不可用请检查数据源配置")
conn = None conn = None
created_time = None created_time = None
is_overflow = False is_overflow = False
@ -150,6 +179,7 @@ class ERPODBCManager:
_instance = None _instance = None
_pool = None _pool = None
_initialized = False
def __new__(cls): def __new__(cls):
"""单例模式""" """单例模式"""
@ -159,22 +189,54 @@ class ERPODBCManager:
def init_app(self, app): def init_app(self, app):
"""初始化在app启动时调用""" """初始化在app启动时调用"""
if self._initialized:
logger.warning("ERP ODBC管理器已初始化跳过重复初始化")
return
config = app.config.get("ERP_ODBC_CONFIG", {}) config = app.config.get("ERP_ODBC_CONFIG", {})
# 创建连接池 # 检查是否启用ODBC
self._pool = PyODBCConnectionPool( if not config.get("enabled", True):
dsn=config.get("dsn", "YHC-test"), logger.info("ERP ODBC功能已禁用配置项 enabled=False")
pool_size=config.get("pool_size", 5), self._pool = None
max_overflow=config.get("max_overflow", 10), self._initialized = True
pool_timeout=config.get("pool_timeout", 30), return
pool_recycle=config.get("pool_recycle", 3600),
)
logger.info("ERP ODBC管理器初始化成功") try:
# 创建连接池(延迟初始化)
self._pool = PyODBCConnectionPool(
dsn=config.get("dsn", "YHC-test"),
pool_size=config.get("pool_size", 5),
max_overflow=config.get("max_overflow", 10),
pool_timeout=config.get("pool_timeout", 30),
pool_recycle=config.get("pool_recycle", 3600),
lazy_init=True, # 延迟初始化,不预创建连接
)
# 测试连接
if self._pool.test_connection():
logger.info("ERP ODBC管理器初始化成功连接测试通过")
else:
logger.warning("ERP ODBC管理器初始化完成但连接测试失败ODBC功能将不可用")
self._initialized = True
except Exception as e:
logger.error(f"ERP ODBC管理器初始化失败: {e}", exc_info=True)
logger.warning("应用将继续启动但ODBC功能将不可用")
self._pool = None
self._initialized = True
def is_available(self) -> bool:
"""检查ODBC连接是否可用"""
return self._pool is not None and self._pool.is_available()
@contextmanager @contextmanager
def get_connection(self): def get_connection(self):
"""获取连接(上下文管理器)""" """获取连接(上下文管理器)"""
if not self.is_available():
raise Exception("ODBC连接不可用请检查数据源配置或联系管理员")
with self._pool.get_connection() as conn: with self._pool.get_connection() as conn:
yield conn yield conn
@ -188,7 +250,13 @@ class ERPODBCManager:
Returns: Returns:
查询结果列表字典格式 查询结果列表字典格式
Raises:
Exception: 当ODBC连接不可用或查询失败时
""" """
if not self.is_available():
raise Exception("ODBC连接不可用无法执行查询")
with self.get_connection() as conn: with self.get_connection() as conn:
cursor = conn.cursor() cursor = conn.cursor()
try: try:
@ -224,7 +292,13 @@ class ERPODBCManager:
Returns: Returns:
影响的行数 影响的行数
Raises:
Exception: 当ODBC连接不可用或执行失败时
""" """
if not self.is_available():
raise Exception("ODBC连接不可用无法执行操作")
with self.get_connection() as conn: with self.get_connection() as conn:
cursor = conn.cursor() cursor = conn.cursor()
try: try:

@ -219,6 +219,7 @@ class BaseConfig:
# ERP ODBC配置 # ERP ODBC配置
ERP_ODBC_CONFIG = { ERP_ODBC_CONFIG = {
"enabled": _get_bool_env("ERP_ODBC_ENABLED", True), # 是否启用ODBC
"dsn": "YHC-test", # ODBC数据源名称 "dsn": "YHC-test", # ODBC数据源名称
"pool_size": 5, # 连接池大小 "pool_size": 5, # 连接池大小
"max_overflow": 10, # 最大溢出连接数 "max_overflow": 10, # 最大溢出连接数

Loading…
Cancel
Save