hsliuping/TradingAgents-CN · error · Exception

AKShare API 调用超时(其他线程占用)

Error message

AKShare API 调用超时(其他线程占用)

What it means

Raised by get_hk_stock_info_akshare when the global _akshare_hk_spot_lock could not be acquired within 60 seconds, meaning another thread is stuck inside the serialized AKShare HK spot call. AKShare HK endpoints are not thread-safe, so access is mutex-serialized per process.

Source

Thrown at tradingagents/dataflows/providers/hk/improved_hk.py:705

        # 尝试从 akshare 获取实时行情
        try:
            # 🔥 使用互斥锁保护 AKShare API 调用(防止并发导致被封禁)
            # 策略:
            # 1. 尝试获取锁(最多等待 60 秒)
            # 2. 获取锁后,先检查缓存是否已被其他线程更新
            # 3. 如果缓存有效,直接使用;否则调用 API

            thread_id = threading.current_thread().name
            logger.info(f"🔒 [AKShare锁-{thread_id}] 尝试获取锁...")

            # 尝试获取锁,最多等待 60 秒
            lock_acquired = _akshare_hk_spot_lock.acquire(timeout=60)

            if not lock_acquired:
                # 超时,返回错误
                logger.error(f"⏰ [AKShare锁-{thread_id}] 获取锁超时(60秒),放弃")
                raise Exception("AKShare API 调用超时(其他线程占用)")

            try:
                logger.info(f"✅ [AKShare锁-{thread_id}] 已获取锁")

                # 获取锁后,检查缓存是否已被其他线程更新
                now = datetime.now()
                cache = _akshare_hk_spot_cache

                if cache['data'] is not None and cache['timestamp'] is not None:
                    elapsed = (now - cache['timestamp']).total_seconds()
                    if elapsed <= cache['ttl']:
                        # 缓存有效(可能是其他线程刚更新的)
                        logger.info(f"⚡ [AKShare缓存-{thread_id}] 使用缓存数据({elapsed:.1f}秒前,可能由其他线程更新)")
                        df = cache['data']
                    else:
                        # 缓存过期,需要调用 API
                        logger.info(f"🔄 [AKShare缓存-{thread_id}] 缓存过期({elapsed:.1f}秒前),调用 API 刷新")
                        df = ak.stock_hk_spot()

View on GitHub (pinned to 74783e8817)

Solutions

  1. Retry after a short wait — the lock is usually released once the slow call finishes
  2. Reduce concurrency for HK AKShare calls (serialize or limit workers to 1-2)
  3. Add per-call timeouts/retries around get_hk_stock_info_akshare
  4. If persistent, switch the HK datasource or check AKShare network health

Example fix

# before
info = get_hk_stock_info_akshare('00700')
# after
for attempt in range(3):
    try:
        info = get_hk_stock_info_akshare('00700'); break
    except Exception as e:
        if '超时' not in str(e): raise
        time.sleep(10)
Defensive patterns

Strategy: retry

Try / catch

for attempt in range(3):
    try:
        info = get_hk_stock_info_akshare(symbol)
        break
    except Exception as e:
        if 'AKShare API 调用超时' not in str(e) or attempt == 2:
            raise
        time.sleep(15)

Prevention

When it happens

Trigger: Multiple concurrent calls to get_hk_stock_info_akshare (e.g. several HK symbols in parallel) while the thread holding the lock blocks on a slow/hung AKShare HTTP request for over 60 seconds.

Common situations: Parallel batch fetching of many HK stocks, AKShare upstream slowness or rate limiting making one call exceed the timeout, thread pools sized larger than the lock can drain.

Related errors


AI-assisted analysis of hsliuping/TradingAgents-CN@74783e8817 (2026-08-28). Data as JSON: /api/errors/676fbfc8f8688415. Report an issue: GitHub.