fix: 禁用DB SSL连接,修复gunicorn preload_app导致的连接池损坏

This commit is contained in:
freedakgmail
2026-07-17 19:12:58 +08:00
parent 9c7d7abdd4
commit 04f8b9f951
2 changed files with 86 additions and 21 deletions
+71 -21
View File
@@ -2,22 +2,55 @@
数据库连接和用户认证
"""
import psycopg2
from psycopg2 import pool
from psycopg2.extras import RealDictCursor
from werkzeug.security import generate_password_hash, check_password_hash
from flask import session
import functools
from config import Config
_pool = None
def init_db_pool():
"""初始化数据库连接池(应用启动时调用一次)"""
global _pool
if _pool is not None:
return
try:
_pool = pool.ThreadedConnectionPool(
minconn=2,
maxconn=20,
host=Config.DB_HOST,
port=Config.DB_PORT,
database=Config.DB_NAME,
user=Config.DB_USER,
password=Config.DB_PASSWORD, sslmode='disable',
)
print(f"[DB] 连接池初始化成功 (min=2, max=20)")
except Exception as e:
print(f"[DB] 连接池初始化失败,降级为逐次建连: {e}")
_pool = None
def get_db():
"""获取数据库连接"""
"""从连接池获取数据库连接(用完必须调用 put_db(conn) 归还)"""
global _pool
if _pool is not None:
try:
conn = _pool.getconn()
if conn and not conn.closed:
conn.autocommit = False
return conn
except Exception as e:
print(f"[DB] 连接池获取失败: {e}")
try:
conn = psycopg2.connect(
host=Config.DB_HOST,
port=Config.DB_PORT,
database=Config.DB_NAME,
user=Config.DB_USER,
password=Config.DB_PASSWORD
password=Config.DB_PASSWORD, sslmode="disable"
)
return conn
except Exception as e:
@@ -25,6 +58,23 @@ def get_db():
return None
def put_db(conn):
"""归还连接到连接池"""
if conn is None:
return
global _pool
if _pool is not None:
try:
_pool.putconn(conn)
return
except Exception:
pass
try:
conn.close()
except Exception:
pass
def login_required(f):
"""登录验证装饰器"""
@functools.wraps(f)
@@ -60,7 +110,7 @@ def db_get_available_cash(user_id):
result = cur.fetchone()
return float(result['available_cash'] or 0) if result else 0
finally:
conn.close()
put_db(conn)
def db_update_available_cash(user_id, amount):
@@ -78,7 +128,7 @@ def db_update_available_cash(user_id, amount):
conn.rollback()
return False, str(e)
finally:
conn.close()
put_db(conn)
# ========== 用户操作 ==========
@@ -111,7 +161,7 @@ def create_user(email, password):
conn.rollback()
return None, str(e)
finally:
conn.close()
put_db(conn)
def verify_user(email, password):
@@ -131,7 +181,7 @@ def verify_user(email, password):
return {'id': user['id'], 'username': user.get('email') or user['username']}, None
finally:
conn.close()
put_db(conn)
def change_user_password(user_id, old_password, new_password):
@@ -158,7 +208,7 @@ def change_user_password(user_id, old_password, new_password):
except Exception as e:
return False, str(e)
finally:
conn.close()
put_db(conn)
# ========== 交易记录操作(数据库版) ==========
@@ -181,7 +231,7 @@ def db_get_trades(user_id):
""", (user_id,))
return cur.fetchall()
finally:
conn.close()
put_db(conn)
def db_get_trade(user_id, trade_id):
@@ -199,7 +249,7 @@ def db_get_trade(user_id, trade_id):
""", (trade_id, user_id))
return cur.fetchone()
finally:
conn.close()
put_db(conn)
def db_add_trade(user_id, data):
@@ -239,7 +289,7 @@ def db_add_trade(user_id, data):
conn.rollback()
return None, str(e)
finally:
conn.close()
put_db(conn)
def db_update_trade(user_id, trade_id, data):
@@ -289,7 +339,7 @@ def db_update_trade(user_id, trade_id, data):
conn.rollback()
return None, str(e)
finally:
conn.close()
put_db(conn)
def db_delete_trade(user_id, trade_id):
@@ -304,7 +354,7 @@ def db_delete_trade(user_id, trade_id):
conn.commit()
return cur.rowcount > 0
finally:
conn.close()
put_db(conn)
# ========== 关注列表操作(数据库版) ==========
@@ -325,7 +375,7 @@ def db_get_watchlist(user_id):
""", (user_id,))
return cur.fetchall()
finally:
conn.close()
put_db(conn)
def db_add_to_watchlist(user_id, code, name):
@@ -348,7 +398,7 @@ def db_add_to_watchlist(user_id, code, name):
conn.rollback()
return None, str(e)
finally:
conn.close()
put_db(conn)
def db_remove_from_watchlist(user_id, code):
@@ -363,7 +413,7 @@ def db_remove_from_watchlist(user_id, code):
conn.commit()
return db_get_watchlist(user_id)
finally:
conn.close()
put_db(conn)
# ========== 分析缓存操作(数据库版) ==========
@@ -389,7 +439,7 @@ def db_get_alerts_cache(user_id):
}
return {'alerts': [], 'lastUpdate': None}
finally:
conn.close()
put_db(conn)
def db_save_alerts_cache(user_id, alerts):
@@ -415,7 +465,7 @@ def db_save_alerts_cache(user_id, alerts):
print(f"保存分析缓存失败: {e}")
return False
finally:
conn.close()
put_db(conn)
# ========== 基本面数据操作(数据库版) ==========
@@ -438,7 +488,7 @@ def db_get_fundamental(code):
""", (code, date.today()))
return cur.fetchone()
finally:
conn.close()
put_db(conn)
def db_save_fundamental(code, data):
@@ -497,7 +547,7 @@ def db_save_fundamental(code, data):
print(f"保存基本面数据失败: {e}")
return False
finally:
conn.close()
put_db(conn)
# ========== 资金流向历史数据操作(数据库版) ==========
@@ -526,7 +576,7 @@ def db_get_fund_flow_history(code):
return [dict(row) for row in rows], latest_date
finally:
conn.close()
put_db(conn)
def db_save_fund_flow_history(code, records):
@@ -584,4 +634,4 @@ def db_save_fund_flow_history(code, records):
print(f"保存资金流向历史失败: {e}")
return False
finally:
conn.close()
put_db(conn)
+15
View File
@@ -0,0 +1,15 @@
"""Gunicorn 生产环境配置"""
import multiprocessing
bind = "0.0.0.0:3333"
workers = min(multiprocessing.cpu_count() * 2 + 1, 4)
worker_class = "gthread"
threads = 4
timeout = 120
keepalive = 5
max_requests = 1000
max_requests_jitter = 50
accesslog = "-"
errorlog = "-"
loglevel = "info"
preload_app = False