From 1d95950b5cfbb044744dbb9f0fcba0210e5a1beb Mon Sep 17 00:00:00 2001 From: dekun Date: Wed, 24 Jun 2026 13:45:39 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=89=8B=E7=BB=AD=E8=B4=B9=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E6=94=B9=E4=B8=BA=E5=90=8E=E5=8F=B0=E6=89=A7=E8=A1=8C?= =?UTF-8?q?=EF=BC=8C=E9=81=BF=E5=85=8D=E9=98=BB=E5=A1=9E=20Web=20=E8=AF=B7?= =?UTF-8?q?=E6=B1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cursor --- app.py | 10 ++++++++-- ctp_fee_worker.py | 36 ++++++++++++++++++++++++++++++++++++ templates/fees.html | 3 +++ 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/app.py b/app.py index f884b47..0c57700 100644 --- a/app.py +++ b/app.py @@ -1560,7 +1560,12 @@ def api_contract_profile(): @require_nav("fees") def fees(): from trading_context import get_trading_mode - from ctp_fee_worker import try_daily_ctp_fee_sync, get_fee_last_sync, fees_synced_today + from ctp_fee_worker import ( + schedule_ctp_fee_sync, + get_fee_last_sync, + fees_synced_today, + fee_sync_in_progress, + ) from vnpy_bridge import ctp_status mode = get_trading_mode(get_setting) @@ -1568,7 +1573,7 @@ def fees(): action = request.form.get("action") if action == "sync_ctp": force = request.form.get("force") == "1" - count, msg = try_daily_ctp_fee_sync( + _, msg = schedule_ctp_fee_sync( mode, get_setting=get_setting, set_setting=set_setting, @@ -1586,6 +1591,7 @@ def fees(): fee_counts=fee_counts, fee_last_sync=get_fee_last_sync(get_setting), fee_synced_today=fees_synced_today(get_setting), + fee_sync_running=fee_sync_in_progress(), ctp_connected=bool(ctp_st.get("connected")), ) diff --git a/ctp_fee_worker.py b/ctp_fee_worker.py index 1ff36f1..2f6ce98 100644 --- a/ctp_fee_worker.py +++ b/ctp_fee_worker.py @@ -16,6 +16,10 @@ CHECK_INTERVAL_SEC = 3600 _sync_lock = threading.Lock() +def fee_sync_in_progress() -> bool: + return _sync_lock.locked() + + def _today_str() -> str: return datetime.now(TZ).date().isoformat() @@ -48,17 +52,49 @@ def try_daily_ctp_fee_sync( if not force and fees_synced_today(get_setting): return 0, "今日已从 CTP 同步过" + t0 = time.monotonic() from ctp_fee_sync import sync_fees_from_ctp count, msg = sync_fees_from_ctp(mode) + elapsed = time.monotonic() - t0 if count > 0: mark_fees_synced(set_setting) + msg = f"{msg}(耗时 {elapsed:.1f} 秒)" logger.info("CTP 手续费每日同步: %s", msg) elif force: + msg = f"{msg}(耗时 {elapsed:.1f} 秒)" logger.warning("CTP 手续费强制同步未写入: %s", msg) return count, msg +def schedule_ctp_fee_sync( + mode: str, + *, + get_setting: Callable[[str, str], str], + set_setting: Callable[[str, str], None], + force: bool = False, +) -> tuple[bool, str]: + """后台线程同步,避免阻塞 Web 请求。""" + if _sync_lock.locked(): + return False, "手续费同步进行中,请稍后再试(约 1~3 分钟)" + + def _run() -> None: + try: + try_daily_ctp_fee_sync( + mode, + get_setting=get_setting, + set_setting=set_setting, + force=force, + ) + except Exception as exc: + logger.exception("CTP 手续费后台同步失败: %s", exc) + + threading.Thread(target=_run, daemon=True, name="ctp-fee-sync-run").start() + if force: + return True, "已在后台开始同步,约 30 秒~2 分钟完成,请稍后刷新本页查看" + return True, "已在后台检查同步,请稍后刷新本页" + + def start_ctp_fee_worker( *, get_mode_fn: Callable[[], str], diff --git a/templates/fees.html b/templates/fees.html index f9db460..5c5fa06 100644 --- a/templates/fees.html +++ b/templates/fees.html @@ -34,6 +34,9 @@ {% if fee_last_sync %} 上次:{{ fee_last_sync[:16] }} {% endif %} + {% if fee_sync_running %} + 同步中… + {% endif %} {% if fee_counts.get('ctp') %} 共 {{ fee_counts.ctp }} 个品种 {% endif %}