修复持仓轮询时 SQLite database is locked 错误。

单连接复用并提交风控写入,启用 WAL 与 busy_timeout,缓存风控表 schema 初始化。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-06-24 10:27:04 +08:00
parent 87aef80594
commit 1688452f3f
3 changed files with 52 additions and 31 deletions
+6 -1
View File
@@ -158,8 +158,13 @@ def expire_old_plans():
# —————————————— 设置读写 —————————————— # —————————————— 设置读写 ——————————————
def get_db(): def get_db():
conn = sqlite3.connect(DB_PATH) conn = sqlite3.connect(DB_PATH, timeout=30)
conn.row_factory = sqlite3.Row conn.row_factory = sqlite3.Row
conn.execute("PRAGMA busy_timeout=30000")
try:
conn.execute("PRAGMA journal_mode=WAL")
except sqlite3.OperationalError:
pass
return conn return conn
+38 -30
View File
@@ -326,18 +326,23 @@ def install_trading(app, *, login_required, get_db, get_setting, set_setting, fe
@login_required @login_required
def api_trading_live(): def api_trading_live():
conn = get_db() conn = get_db()
init_strategy_tables(conn) try:
mode = get_trading_mode(get_setting) init_strategy_tables(conn)
ctp_st = ctp_status(mode) mode = get_trading_mode(get_setting)
rows = _build_trading_live_rows(conn) ctp_st = ctp_status(mode)
conn.close() rows = _build_trading_live_rows(conn)
return jsonify({ capital = _capital(conn)
"rows": rows, risk = get_risk_status(conn)
"capital": _capital(get_db()), conn.commit()
"ctp_status": ctp_st, return jsonify({
"trading_mode_label": trading_mode_label(get_setting), "rows": rows,
"risk_status": get_risk_status(get_db()), "capital": capital,
}) "ctp_status": ctp_st,
"trading_mode_label": trading_mode_label(get_setting),
"risk_status": risk,
})
finally:
conn.close()
@app.route("/api/trading/close", methods=["POST"]) @app.route("/api/trading/close", methods=["POST"])
@login_required @login_required
@@ -595,24 +600,27 @@ def install_trading(app, *, login_required, get_db, get_setting, set_setting, fe
@login_required @login_required
def api_account_snapshot(): def api_account_snapshot():
conn = get_db() conn = get_db()
init_strategy_tables(conn) try:
mode = get_trading_mode(get_setting) init_strategy_tables(conn)
ctp_st = ctp_status(mode) mode = get_trading_mode(get_setting)
capital = _capital(conn) ctp_st = ctp_status(mode)
risk = get_risk_status(conn) capital = _capital(conn)
ctp_acc = _ctp_account(mode) if ctp_st.get("connected") else {} risk = get_risk_status(conn)
positions = _ctp_positions(mode) if ctp_st.get("connected") else [] conn.commit()
conn.close() ctp_acc = _ctp_account(mode) if ctp_st.get("connected") else {}
return jsonify({ positions = _ctp_positions(mode) if ctp_st.get("connected") else []
"capital": capital, return jsonify({
"trading_mode": mode, "capital": capital,
"trading_mode_label": trading_mode_label(get_setting), "trading_mode": mode,
"sizing_mode": get_sizing_mode(get_setting), "trading_mode_label": trading_mode_label(get_setting),
"risk_status": risk, "sizing_mode": get_sizing_mode(get_setting),
"ctp_status": ctp_st, "risk_status": risk,
"ctp_account": ctp_acc, "ctp_status": ctp_st,
"positions": positions, "ctp_account": ctp_acc,
}) "positions": positions,
})
finally:
conn.close()
@app.route("/api/recommend/list") @app.route("/api/recommend/list")
@login_required @login_required
+8
View File
@@ -76,7 +76,13 @@ def trading_day_reset_hour() -> int:
return 8 return 8
_SCHEMA_READY = False
def ensure_account_risk_schema(conn) -> None: def ensure_account_risk_schema(conn) -> None:
global _SCHEMA_READY
if _SCHEMA_READY:
return
conn.execute( conn.execute(
"""CREATE TABLE IF NOT EXISTS account_risk_state ( """CREATE TABLE IF NOT EXISTS account_risk_state (
id INTEGER PRIMARY KEY CHECK (id = 1), id INTEGER PRIMARY KEY CHECK (id = 1),
@@ -93,6 +99,8 @@ def ensure_account_risk_schema(conn) -> None:
conn.execute( conn.execute(
"INSERT INTO account_risk_state (id, trading_day, manual_close_count, daily_frozen) VALUES (1, '', 0, 0)" "INSERT INTO account_risk_state (id, trading_day, manual_close_count, daily_frozen) VALUES (1, '', 0, 0)"
) )
conn.commit()
_SCHEMA_READY = True
def _row_get(row, key, default=None): def _row_get(row, key, default=None):