修复模拟盘卖币握锁导致 database is locked 与中控超时离线。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-10-07 11:04:06 +08:00
parent 066c90fd96
commit 80ef5ceccb
7 changed files with 173 additions and 126 deletions
+77 -38
View File
@@ -303,60 +303,99 @@ def rollback_bought_coin_to_usdt(
def sell_residual_after_option_flat(
conn: sqlite3.Connection,
conn_or_get_db: Any,
ex: Any,
*,
underlying: str,
inst_id: str | None = None,
) -> dict[str, Any]:
"""期权已平:卖掉本桥残留标的币;优先关闭 matching holding/pending 桥."""
ensure_bridge_table(conn)
bridges = list_open_bridges(conn)
target = None
for b in bridges:
if str(b.get("status")) in (BRIDGE_HOLDING, BRIDGE_PENDING_SELL, BRIDGE_BOUGHT):
if not underlying or str(b.get("underlying") or "").upper() == underlying.upper():
target = b
break
# 卖币(模拟盘)会另开连接写钱包,须先释放本连接事务锁,否则 database is locked
try:
conn.commit()
except Exception:
pass
"""期权已平:卖掉本桥残留标的币;优先关闭 matching holding/pending 桥.
可传 get_db 可调用对象(推荐)或已打开的 Connection。
卖币(尤其模拟盘写钱包)期间绝不握着业务连接,否则会 database is locked。
"""
get_db = conn_or_get_db if callable(conn_or_get_db) else None
bid: int | None = None
if get_db is not None:
conn = get_db()
try:
ensure_bridge_table(conn)
bridges = list_open_bridges(conn)
for b in bridges:
if str(b.get("status")) in (BRIDGE_HOLDING, BRIDGE_PENDING_SELL, BRIDGE_BOUGHT):
if not underlying or str(b.get("underlying") or "").upper() == underlying.upper():
bid = int(b["id"])
break
try:
conn.commit()
except Exception:
pass
finally:
try:
conn.close()
except Exception:
pass
else:
conn = conn_or_get_db
ensure_bridge_table(conn)
bridges = list_open_bridges(conn)
for b in bridges:
if str(b.get("status")) in (BRIDGE_HOLDING, BRIDGE_PENDING_SELL, BRIDGE_BOUGHT):
if not underlying or str(b.get("underlying") or "").upper() == underlying.upper():
bid = int(b["id"])
break
try:
conn.commit()
except Exception:
pass
# 此处无业务连接:模拟盘 convert 可安全另开写钱包
sell = spot_market_sell_coin_to_usdt(ex, underlying=underlying)
if target is None:
if bid is None:
if not sell.get("ok"):
msg = str(sell.get("msg") or "")
if "无可用" in msg or "过小" in msg:
return {"ok": True, "msg": "无残留币需卖回", "skipped": True}
return {"ok": False, "msg": msg, "bridge_status": BRIDGE_PENDING_SELL}
return {"ok": True, "sell": sell, "bridge_status": None}
bid = int(target["id"])
if not sell.get("ok"):
def _apply_bridge(c: sqlite3.Connection) -> dict[str, Any]:
if not sell.get("ok"):
update_bridge(
c,
bid,
status=BRIDGE_PENDING_SELL,
inst_id=inst_id,
message=str(sell.get("msg") or "卖回 USDT 失败"),
)
return {
"ok": False,
"msg": sell.get("msg") or "卖回 USDT 失败",
"bridge_id": bid,
"bridge_status": BRIDGE_PENDING_SELL,
}
update_bridge(
conn,
c,
bid,
status=BRIDGE_PENDING_SELL,
status=BRIDGE_CLOSED,
sell_ord_id=str(sell.get("ord_id") or ""),
coin_sold=_safe_float(sell.get("coin_sold")),
inst_id=inst_id,
message=str(sell.get("msg") or "卖回 USDT 失败"),
message="期权已平,币已卖回 USDT",
close=True,
)
return {
"ok": False,
"msg": sell.get("msg") or "卖回 USDT 失败",
"bridge_id": bid,
"bridge_status": BRIDGE_PENDING_SELL,
}
update_bridge(
conn,
bid,
status=BRIDGE_CLOSED,
sell_ord_id=str(sell.get("ord_id") or ""),
coin_sold=_safe_float(sell.get("coin_sold")),
inst_id=inst_id,
message="期权已平,币已卖回 USDT",
close=True,
)
return {"ok": True, "sell": sell, "bridge_id": bid, "bridge_status": BRIDGE_CLOSED}
return {"ok": True, "sell": sell, "bridge_id": bid, "bridge_status": BRIDGE_CLOSED}
if get_db is not None:
conn2 = get_db()
try:
return _apply_bridge(conn2)
finally:
try:
conn2.close()
except Exception:
pass
return _apply_bridge(conn_or_get_db)
def bridge_blocks_new_open_msg(conn: sqlite3.Connection) -> str | None: