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