From d04d9d5052428d3f803ad7de804869212276adcd Mon Sep 17 00:00:00 2001 From: xxm Date: Fri, 28 Aug 2026 14:59:41 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20busy=5Ftimeout=E8=A1=A5=E4=B8=81?= =?UTF-8?q?=E5=9B=9E=E5=BD=92=E2=80=94=E2=80=94conn=E6=9C=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=E6=94=B9db/=5Fconn=E7=AD=89=E5=AE=9E=E9=99=85?= =?UTF-8?q?=E5=8F=98=E9=87=8F(18=E6=96=87=E4=BB=B6,=E7=9F=A5=E5=BE=AE?= =?UTF-8?q?=E5=8D=A1t=5F62624130/t=5Ff244e050=E5=8F=91=E7=8E=B0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- deploy/profile-scripts/capital_flow_collector.py | 2 +- deploy/profile-scripts/generate_report.py | 2 +- deploy/profile-scripts/kanban_xmpp_bridge.py | 2 +- deploy/profile-scripts/leader_scanner.py | 2 +- deploy/profile-scripts/mo_alphasift_bridge.py | 2 +- deploy/profile-scripts/mo_data.py | 4 ++-- deploy/profile-scripts/mofin_db.py | 4 ++-- deploy/profile-scripts/morning_health_check.py | 4 ++-- deploy/profile-scripts/per_stock_reassess.py | 8 ++++---- deploy/profile-scripts/pre-flight-check.py | 2 +- deploy/profile-scripts/prepare_recommendation.py | 2 +- deploy/profile-scripts/run_all_tests.py | 4 ++-- deploy/profile-scripts/stale_detector.py | 6 +++--- deploy/profile-scripts/stock_quote.py | 2 +- deploy/profile-scripts/strategy_alert.py | 2 +- deploy/profile-scripts/strategy_lifecycle.py | 4 ++-- deploy/profile-scripts/vacuum_state_db.py | 2 +- deploy/profile-scripts/verify_reassess_pipeline.py | 2 +- 18 files changed, 28 insertions(+), 28 deletions(-) diff --git a/deploy/profile-scripts/capital_flow_collector.py b/deploy/profile-scripts/capital_flow_collector.py index c7334edf..737c27cf 100644 --- a/deploy/profile-scripts/capital_flow_collector.py +++ b/deploy/profile-scripts/capital_flow_collector.py @@ -155,7 +155,7 @@ def main(): try: import sqlite3 _db = sqlite3.connect("/home/hmo/MoFin/data/mofin.db") - conn.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) + _db.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) for row in _db.execute("SELECT DISTINCT code FROM holdings WHERE is_active=1").fetchall(): if row[0]: codes.add(row[0]) for row in _db.execute("SELECT DISTINCT code FROM holding_strategies WHERE status='active' AND decision_type='自选策略'").fetchall(): diff --git a/deploy/profile-scripts/generate_report.py b/deploy/profile-scripts/generate_report.py index 4ad028a2..7bb275d6 100644 --- a/deploy/profile-scripts/generate_report.py +++ b/deploy/profile-scripts/generate_report.py @@ -98,7 +98,7 @@ def main(): try: import sqlite3 _conn = sqlite3.connect("/home/hmo/web-dashboard/data/mofin.db") - conn.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) + _conn.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) _actionable = _conn.execute( "SELECT hs.code, lp.price, hs.entry_low, hs.entry_high FROM holding_strategies hs " "LEFT JOIN live_prices lp ON hs.code = lp.code " diff --git a/deploy/profile-scripts/kanban_xmpp_bridge.py b/deploy/profile-scripts/kanban_xmpp_bridge.py index ed32b851..56bfc709 100644 --- a/deploy/profile-scripts/kanban_xmpp_bridge.py +++ b/deploy/profile-scripts/kanban_xmpp_bridge.py @@ -51,7 +51,7 @@ def main(): return notified = _load_state() db = sqlite3.connect(KANBAN_DB) - conn.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) + db.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) rows = db.execute( "SELECT id, title, assignee, created_by FROM tasks " "WHERE status='ready' AND assignee IN (%s) ORDER BY created_at" diff --git a/deploy/profile-scripts/leader_scanner.py b/deploy/profile-scripts/leader_scanner.py index fb04bce8..ec372f21 100644 --- a/deploy/profile-scripts/leader_scanner.py +++ b/deploy/profile-scripts/leader_scanner.py @@ -41,7 +41,7 @@ def scan_leaders(): return [] c = sqlite3.connect(DB) - conn.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) + c.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) # 最新交易日 row = c.execute("SELECT MAX(date) FROM stock_indicators").fetchone() if not row or not row[0]: diff --git a/deploy/profile-scripts/mo_alphasift_bridge.py b/deploy/profile-scripts/mo_alphasift_bridge.py index 57b663f5..fdc971c2 100644 --- a/deploy/profile-scripts/mo_alphasift_bridge.py +++ b/deploy/profile-scripts/mo_alphasift_bridge.py @@ -59,7 +59,7 @@ def get_existing_codes(): try: import sqlite3 db = sqlite3.connect(str(MOFIN_DATA / "mofin.db")) - conn.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) + db.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) for row in db.execute("SELECT code FROM watchlist_stocks WHERE is_active=1"): codes.add(str(row[0]).strip()) for row in db.execute("SELECT code FROM holdings"): diff --git a/deploy/profile-scripts/mo_data.py b/deploy/profile-scripts/mo_data.py index 48cb39f2..64f5f37e 100644 --- a/deploy/profile-scripts/mo_data.py +++ b/deploy/profile-scripts/mo_data.py @@ -23,7 +23,7 @@ SCRIPT_DIR = Path('/home/hmo/MoFin/scripts') def _get_db(): db = sqlite3.connect(DB_PATH) - conn.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) + db.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) db.row_factory = sqlite3.Row return db @@ -288,7 +288,7 @@ def write_cash_log(cash_before, cash_after, frozen_before, frozen_after, """记录现金变更到 cash_log 表。""" change_amount = round(cash_after - cash_before, 2) if cash_after is not None and cash_before is not None else 0 db = sqlite3.connect(DB_PATH) - conn.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) + db.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) try: cur = db.execute( """INSERT INTO cash_log diff --git a/deploy/profile-scripts/mofin_db.py b/deploy/profile-scripts/mofin_db.py index dd1c6110..a6e32a46 100644 --- a/deploy/profile-scripts/mofin_db.py +++ b/deploy/profile-scripts/mofin_db.py @@ -1119,7 +1119,7 @@ def get_price_from_db(code: str) -> tuple[float | None, float | None]: """ try: db = sqlite3.connect('/home/hmo/web-dashboard/data/mofin.db') - conn.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) + db.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) db.row_factory = sqlite3.Row row = db.execute( "SELECT price, change_pct FROM holdings WHERE code=? AND is_active=1", (str(code),) @@ -1143,7 +1143,7 @@ def get_prices_batch_from_db(codes: list[str]) -> dict: return results try: db = sqlite3.connect('/home/hmo/web-dashboard/data/mofin.db') - conn.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) + db.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) db.row_factory = sqlite3.Row for code in codes: row = db.execute( diff --git a/deploy/profile-scripts/morning_health_check.py b/deploy/profile-scripts/morning_health_check.py index bdab5c2a..c3bc96e9 100644 --- a/deploy/profile-scripts/morning_health_check.py +++ b/deploy/profile-scripts/morning_health_check.py @@ -807,7 +807,7 @@ def main(): # 保存历史到DB try: conn_hist = sqlite3.connect(str(DB_PATH)) - conn.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) + conn_hist.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) details = json.dumps([e for e in ctx["report"] if e["level"] in ("critical", "error")]) conn_hist.execute( "INSERT INTO health_check_log (ok_count, warn_count, error_count, critical_count, duration_s, details) " @@ -838,7 +838,7 @@ def main(): # 检查是否有执行器升级来的TODO(通知失败挂起的) try: conn2 = sqlite3.connect(str(DB_PATH)) - conn.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) + conn2.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) needs_llm = conn2.execute( "SELECT id, title, priority, created_at, note FROM todos " "WHERE status='needs_llm' " diff --git a/deploy/profile-scripts/per_stock_reassess.py b/deploy/profile-scripts/per_stock_reassess.py index d0ebd7e6..fbae791d 100644 --- a/deploy/profile-scripts/per_stock_reassess.py +++ b/deploy/profile-scripts/per_stock_reassess.py @@ -273,7 +273,7 @@ def main(): # 不在 decisions 中的自选股 → 从 holding_strategies 构建entry import sqlite3 _db = sqlite3.connect('/home/hmo/MoFin/data/mofin.db') - conn.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) + _db.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) _db.row_factory = sqlite3.Row _wl = _db.execute("SELECT * FROM holding_strategies WHERE code=? AND status='active' AND decision_type='自选策略'", (code,)).fetchone() _db.close() @@ -308,7 +308,7 @@ def main(): price = 0 import sqlite3 db = sqlite3.connect('/home/hmo/web-dashboard/data/mofin.db') - conn.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) + db.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) db.row_factory = sqlite3.Row row = db.execute("SELECT price FROM holdings WHERE code=? AND is_active=1", (code_raw,)).fetchone() if not row: @@ -562,7 +562,7 @@ def main(): from datetime import datetime as _dt import sqlite3 _db2 = sqlite3.connect('/home/hmo/web-dashboard/data/mofin.db') - conn.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) + _db2.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) for _code in codes: _entry = decisions_map.get(_code) if _entry and _entry.get("is_watchlist"): @@ -626,7 +626,7 @@ def scan_watchlist_stocks(): DB = '/home/hmo/web-dashboard/data/mofin.db' db = sqlite3.connect(DB) - conn.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) + db.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) db.row_factory = sqlite3.Row rows = db.execute( diff --git a/deploy/profile-scripts/pre-flight-check.py b/deploy/profile-scripts/pre-flight-check.py index ecbd44c6..3e56c444 100644 --- a/deploy/profile-scripts/pre-flight-check.py +++ b/deploy/profile-scripts/pre-flight-check.py @@ -67,7 +67,7 @@ def check_data_freshness(): try: import sqlite3 c = sqlite3.connect(str(WEB_DATA / "mofin.db")) - conn.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) + c.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) row = c.execute("SELECT MAX(updated_at) FROM holding_strategies WHERE status IN ('active','updated')").fetchone() c.close() if row and row[0]: diff --git a/deploy/profile-scripts/prepare_recommendation.py b/deploy/profile-scripts/prepare_recommendation.py index a0b60957..84908b9d 100644 --- a/deploy/profile-scripts/prepare_recommendation.py +++ b/deploy/profile-scripts/prepare_recommendation.py @@ -23,7 +23,7 @@ SCRIPTS_DIR = os.path.dirname(os.path.abspath(__file__)) def get_stock_info(code): """从数据库获取股票信息""" db = sqlite3.connect(DB_PATH) - conn.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) + db.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) db.row_factory = sqlite3.Row try: # 检查持仓 diff --git a/deploy/profile-scripts/run_all_tests.py b/deploy/profile-scripts/run_all_tests.py index 3de4d64d..b36350b7 100644 --- a/deploy/profile-scripts/run_all_tests.py +++ b/deploy/profile-scripts/run_all_tests.py @@ -94,7 +94,7 @@ test("frozen_cash 已清零", pf.get('frozen_cash', 0) < 1, f"frozen_cash={pf.ge print("\n--- 6. P&L ---") import sqlite3 db = sqlite3.connect('/home/hmo/web-dashboard/data/mofin.db') -conn.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) +db.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) rows = db.execute("SELECT code, name, cost, price, shares, currency FROM holdings WHERE is_active=1 AND shares>0").fetchall() pnl_issues = [] for r in rows: @@ -112,7 +112,7 @@ db.close() # ── 7. DB 完整性 ── print("\n--- 7. DB 完整性 ---") db = sqlite3.connect('/home/hmo/web-dashboard/data/mofin.db') -conn.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) +db.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) n_holds = db.execute("SELECT COUNT(*) FROM holdings WHERE is_active=1").fetchone()[0] n_strat = db.execute("SELECT COUNT(*) FROM holding_strategies WHERE status IN ('active','updated')").fetchone()[0] n_wl = db.execute("SELECT COUNT(*) FROM watchlist_stocks WHERE is_active=1").fetchone()[0] diff --git a/deploy/profile-scripts/stale_detector.py b/deploy/profile-scripts/stale_detector.py index 813a223a..b533c134 100644 --- a/deploy/profile-scripts/stale_detector.py +++ b/deploy/profile-scripts/stale_detector.py @@ -84,7 +84,7 @@ def main(): try: import sqlite3 db = sqlite3.connect('/home/hmo/MoFin/data/mofin.db') - conn.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) + db.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) db.row_factory = sqlite3.Row wl_rows = db.execute( "SELECT code, name, entry_low, entry_high, stop_loss, take_profit, rr_ratio, timing_signal, action " @@ -125,7 +125,7 @@ def main(): try: import subprocess, sqlite3 db = sqlite3.connect('/home/hmo/MoFin/data/mofin.db') - conn.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) + db.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) db.row_factory = sqlite3.Row wl_stocks = db.execute( "SELECT code, name, entry_low, entry_high " @@ -184,7 +184,7 @@ def main(): to_check = [d for d in decisions_list if (d.get("entry_low") is not None or d.get("entry_high") is not None) and d.get("status") not in EXCLUDED_STATUSES] # 重新合并自选(从 holding_strategies 读) db2 = sqlite3.connect('/home/hmo/MoFin/data/mofin.db') - conn.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) + db2.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) db2.row_factory = sqlite3.Row wl_rows2 = db2.execute( "SELECT code, name, entry_low, entry_high, stop_loss, take_profit, rr_ratio, timing_signal, action " diff --git a/deploy/profile-scripts/stock_quote.py b/deploy/profile-scripts/stock_quote.py index 59fa2417..cbd9db81 100644 --- a/deploy/profile-scripts/stock_quote.py +++ b/deploy/profile-scripts/stock_quote.py @@ -303,7 +303,7 @@ def _get_name_from_cache(code): try: import sqlite3 _db = sqlite3.connect(str(DATA_DIR / "mofin.db")) - conn.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) + _db.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) _db.row_factory = sqlite3.Row row = _db.execute("SELECT name FROM watchlist_stocks WHERE code=? AND is_active=1", (code,)).fetchone() _db.close() diff --git a/deploy/profile-scripts/strategy_alert.py b/deploy/profile-scripts/strategy_alert.py index 27048fdb..0109239f 100644 --- a/deploy/profile-scripts/strategy_alert.py +++ b/deploy/profile-scripts/strategy_alert.py @@ -37,7 +37,7 @@ ORANGE_PNL_RATIO = 0.5 # 盈亏比 < 0.5(赚的越来越少亏的越来越 def rolling_stats(version, days=60): """从 strategy_research 提取该策略近期交易的滚动胜率/盈亏比""" c = sqlite3.connect(DB) - conn.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) + c.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) rows = c.execute( "SELECT results_json FROM strategy_research WHERE version=? ORDER BY period_tag DESC LIMIT 1", (version,) diff --git a/deploy/profile-scripts/strategy_lifecycle.py b/deploy/profile-scripts/strategy_lifecycle.py index 88241c64..38c488c1 100644 --- a/deploy/profile-scripts/strategy_lifecycle.py +++ b/deploy/profile-scripts/strategy_lifecycle.py @@ -749,7 +749,7 @@ def batch_fetch_prices(codes): try: import sqlite3 db = sqlite3.connect('/home/hmo/web-dashboard/data/mofin.db') - conn.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) + db.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) db.row_factory = sqlite3.Row for raw_code in codes: raw_code = str(raw_code).split('_')[0] @@ -819,7 +819,7 @@ def get_price_tencent(code): try: import sqlite3 db = sqlite3.connect('/home/hmo/web-dashboard/data/mofin.db') - conn.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) + db.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) db.row_factory = sqlite3.Row row = db.execute("SELECT price FROM holdings WHERE code=? AND is_active=1", (raw_code,)).fetchone() if not row: diff --git a/deploy/profile-scripts/vacuum_state_db.py b/deploy/profile-scripts/vacuum_state_db.py index 8cdf25eb..ae0f6bcc 100644 --- a/deploy/profile-scripts/vacuum_state_db.py +++ b/deploy/profile-scripts/vacuum_state_db.py @@ -23,7 +23,7 @@ for db_path in DBS: size_before = os.path.getsize(db_path) / 1024 / 1024 try: c = sqlite3.connect(db_path) - conn.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) + c.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) c.execute("PRAGMA auto_vacuum=2") # 只做incremental vacuum,不做full vacuum(耗时太长) c.execute("PRAGMA incremental_vacuum(50000)") diff --git a/deploy/profile-scripts/verify_reassess_pipeline.py b/deploy/profile-scripts/verify_reassess_pipeline.py index 29e663c9..c51fc4d0 100644 --- a/deploy/profile-scripts/verify_reassess_pipeline.py +++ b/deploy/profile-scripts/verify_reassess_pipeline.py @@ -81,7 +81,7 @@ def check_cron_jobs(): continue try: c = sqlite3.connect(str(db_path)) - conn.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) + c.execute("PRAGMA busy_timeout=30000") # 2026-08-28 防并发写锁(DB损坏教训) for row in c.execute(""" SELECT id, name, last_status, last_run_at, enabled FROM cron_jobs WHERE enabled=1