修复复盘列表与统计并行同步撞锁导致模拟盘加载失败。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -66,21 +66,28 @@ def _safe_float(v: Any) -> Optional[float]:
|
||||
|
||||
|
||||
def get_sync_state(conn: sqlite3.Connection, key: str) -> Optional[str]:
|
||||
row = conn.execute(
|
||||
"SELECT value FROM options_review_sync_state WHERE key=?", (key,)
|
||||
).fetchone()
|
||||
try:
|
||||
row = conn.execute(
|
||||
"SELECT value FROM options_review_sync_state WHERE key=?", (key,)
|
||||
).fetchone()
|
||||
except sqlite3.OperationalError:
|
||||
return None
|
||||
return str(row["value"]) if row and row["value"] is not None else None
|
||||
|
||||
|
||||
def set_sync_state(conn: sqlite3.Connection, key: str, value: str) -> None:
|
||||
conn.execute(
|
||||
"""
|
||||
INSERT INTO options_review_sync_state(key, value, updated_at)
|
||||
VALUES (?, ?, ?)
|
||||
ON CONFLICT(key) DO UPDATE SET value=excluded.value, updated_at=excluded.updated_at
|
||||
""",
|
||||
(key, value, _now_str()),
|
||||
)
|
||||
try:
|
||||
conn.execute(
|
||||
"""
|
||||
INSERT INTO options_review_sync_state(key, value, updated_at)
|
||||
VALUES (?, ?, ?)
|
||||
ON CONFLICT(key) DO UPDATE SET value=excluded.value, updated_at=excluded.updated_at
|
||||
""",
|
||||
(key, value, _now_str()),
|
||||
)
|
||||
except sqlite3.OperationalError:
|
||||
# 列表/统计并发刷新时可能撞锁;标记失败不阻断读列表
|
||||
pass
|
||||
|
||||
|
||||
def _purge_review_trade_by_key(conn: sqlite3.Connection, history_key: str) -> bool:
|
||||
@@ -627,8 +634,16 @@ def ensure_local_review_synced(
|
||||
repair_swapped_closed_at_signal_note,
|
||||
)
|
||||
|
||||
ts_migrate = migrate_options_utc_wall_clock_to_app(conn)
|
||||
note_swap = repair_swapped_closed_at_signal_note(conn)
|
||||
ts_migrate: dict[str, Any] = {}
|
||||
note_swap: dict[str, Any] = {}
|
||||
try:
|
||||
ts_migrate = migrate_options_utc_wall_clock_to_app(conn)
|
||||
except Exception as e:
|
||||
ts_migrate = {"ok": False, "msg": str(e)}
|
||||
try:
|
||||
note_swap = repair_swapped_closed_at_signal_note(conn)
|
||||
except Exception as e:
|
||||
note_swap = {"ok": False, "msg": str(e)}
|
||||
if backfill_exchange_pnl and ex is not None:
|
||||
try:
|
||||
from lib.exchange.okx_options_lib import fetch_all_option_positions_history
|
||||
@@ -640,7 +655,10 @@ def ensure_local_review_synced(
|
||||
backfill_closed_options_realized_pnl_from_history(conn, hist)
|
||||
except Exception:
|
||||
pass
|
||||
out = sync_all_review_sources(conn, ex=ex, from_exchange=False)
|
||||
try:
|
||||
out = sync_all_review_sources(conn, ex=ex, from_exchange=False)
|
||||
except sqlite3.OperationalError as e:
|
||||
out = {"ok": False, "msg": f"sync locked: {e}"}
|
||||
if isinstance(out, dict):
|
||||
out["ts_migrate"] = ts_migrate
|
||||
out["note_swap"] = note_swap
|
||||
|
||||
Reference in New Issue
Block a user