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 %}