From e81a69e2e6d9780eb1ad94c2efaa6cd2e6c07ed7 Mon Sep 17 00:00:00 2001 From: aaron <> Date: Wed, 12 Mar 2025 15:48:33 +0800 Subject: [PATCH] update --- app/models/coupon.py | 1 + app/models/database.py | 69 +++++++++++++++++++++++++++++++++++------ jobs.sqlite | Bin 24576 -> 24576 bytes 3 files changed, 61 insertions(+), 9 deletions(-) diff --git a/app/models/coupon.py b/app/models/coupon.py index 2bd7289..481e32e 100644 --- a/app/models/coupon.py +++ b/app/models/coupon.py @@ -56,6 +56,7 @@ class CouponInfo(BaseModel): id: int name: str amount: float + expire_time: datetime coupon_type: CouponType create_time: datetime diff --git a/app/models/database.py b/app/models/database.py index 8ae80b6..6881846 100644 --- a/app/models/database.py +++ b/app/models/database.py @@ -1,4 +1,4 @@ -from sqlalchemy import create_engine, event +from sqlalchemy import create_engine, event, text from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker, scoped_session from app.core.config import settings @@ -22,7 +22,15 @@ engine = create_engine( pool_size=10, # 连接池大小 max_overflow=20, # 允许的最大连接数超出pool_size的数量 pool_timeout=30, # 获取连接的超时时间(秒) - echo_pool=settings.DEBUG # 在调试模式下记录连接池事件 + echo_pool=settings.DEBUG, # 在调试模式下记录连接池事件 + # 添加以下参数以增强连接稳定性 + pool_reset_on_return='commit', # 在连接返回池时重置连接状态 + isolation_level='READ COMMITTED', # 设置事务隔离级别 + connect_args={ + 'connect_timeout': 10, # 连接超时时间(秒) + 'read_timeout': 30, # 读取超时时间(秒) + 'write_timeout': 30 # 写入超时时间(秒) + } ) # 创建线程安全的会话工厂 @@ -59,10 +67,14 @@ def checkout(dbapi_connection, connection_record, connection_proxy): # 执行简单查询测试连接 cursor = dbapi_connection.cursor() cursor.execute("SELECT 1") + cursor.fetchone() # 确保实际获取结果 cursor.close() except Exception as e: - # 如果连接无效,断开它 + # 如果连接无效,断开它并尝试重新连接 logger.warning(f"检测到无效的数据库连接: {str(e)}") + # 标记连接为无效 + connection_record.invalidate() + # 强制处理连接池 connection_proxy._pool.dispose() raise @@ -113,7 +125,25 @@ def after_cursor_execute(conn, cursor, statement, parameters, context, executema def get_db(): """获取数据库会话""" session_id = threading.get_ident() - session = SessionLocal() + db = None + retry_count = 0 + max_retries = 3 + + while retry_count < max_retries: + try: + db = SessionLocal() + # 测试连接是否有效 + db.execute(text("SELECT 1")) + break + except Exception as e: + retry_count += 1 + if db: + db.close() + if retry_count >= max_retries: + logger.error(f"无法建立数据库连接,已重试 {retry_count} 次: {str(e)}") + raise + logger.warning(f"数据库连接失败,正在重试 ({retry_count}/{max_retries}): {str(e)}") + time.sleep(0.5) # 短暂延迟后重试 # 记录活跃会话 with session_lock: @@ -123,10 +153,11 @@ def get_db(): } try: - yield session + yield db finally: # 关闭会话并从活跃会话中移除 - session.close() + if db: + db.close() with session_lock: if session_id in active_sessions: del active_sessions[session_id] @@ -134,9 +165,27 @@ def get_db(): @contextmanager def get_db_context(): """上下文管理器版本的get_db,用于非依赖项场景""" - session = SessionLocal() + session = None + retry_count = 0 + max_retries = 3 session_id = threading.get_ident() + while retry_count < max_retries: + try: + session = SessionLocal() + # 测试连接是否有效 + session.execute(text("SELECT 1")) + break + except Exception as e: + retry_count += 1 + if session: + session.close() + if retry_count >= max_retries: + logger.error(f"无法建立数据库连接,已重试 {retry_count} 次: {str(e)}") + raise + logger.warning(f"数据库连接失败,正在重试 ({retry_count}/{max_retries}): {str(e)}") + time.sleep(0.5) # 短暂延迟后重试 + # 记录活跃会话 with session_lock: active_sessions[session_id] = { @@ -148,10 +197,12 @@ def get_db_context(): yield session session.commit() except Exception as e: - session.rollback() + if session: + session.rollback() raise e finally: - session.close() + if session: + session.close() with session_lock: if session_id in active_sessions: del active_sessions[session_id] diff --git a/jobs.sqlite b/jobs.sqlite index 4be9602c08688d48e83a585a6285d26f73f07702..ee96d22ab83c18477f246f3493ae45fe04fa70d6 100644 GIT binary patch delta 19 bcmZoTz}Rqrae_4C)QK|Aj8iuzEQkjHNh1eZ delta 19 acmZoTz}Rqrae_2s??f4A#@>wy3*rGts|QK|