You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FastAPI+Next.js中WebSocket进度消息延迟送达问题求助

WebSocket进度消息延迟接收问题排查与解决

原因分析

问题核心在于后端异步事件循环被同步阻塞操作占用:
FastAPI基于asyncio事件循环,所有异步任务(包括WebSocket消息发送)都依赖事件循环调度。但你的代码中存在大量同步阻塞操作:

  • 文件读取:file.file.read()是同步IO操作,直接阻塞事件循环
  • PDF/Word解析:extract_text_from_pdf、Document.LoadFromFile及后续遍历操作均为同步CPU密集型/IO操作,长时间占用事件循环
    这些操作导致WebSocket的send_json任务无法被及时调度,所有进度消息积压,直到整个请求处理完成后才一次性发送到前端。

解决方案

1. 异步化所有同步阻塞操作

将同步IO/CPU密集型操作封装到线程池中执行,避免阻塞asyncio事件循环:

import asyncio

# 修改文件读取逻辑
content = await asyncio.to_thread(file.file.read)
with open(file_location, "wb") as file_object:
    file_object.write(content)

# 修改PDF解析逻辑
text = await asyncio.to_thread(extract_text_from_pdf, file_location)

# 将Word解析逻辑抽为单独函数,用线程池执行
def parse_word_file(file_location, chunk_text, chunks):
    document = Document()
    document.LoadFromFile(file_location)
    for index in range(document.Sections.Count):
        section = document.Sections.get_Item(index)
        for id in range(section.Paragraphs.Count):
            paragraph = section.Paragraphs.get_Item(id)
            if len(chunk_text) + len(paragraph.Text) < CHUNK_SIZE:
                chunk_text += paragraph.Text
            else:
                chunks.append(chunk_text)
                chunk_text = paragraph.Text
    return chunk_text, chunks

# 在主函数中调用
chunk_text, chunks = await asyncio.to_thread(parse_word_file, file_location, chunk_text, chunks)

2. 主动让出事件循环

在每次发送WebSocket消息后,主动让出事件循环,确保消息能被及时推送:

await websocket.send_json({'type': 'pleadings', 'percentage': percentage})
# 让出事件循环,优先执行WebSocket发送任务
await asyncio.sleep(0)

3. 验证WebSocket连接池实现

确保manager.connection_pool中存储的是异步WebSocket实例,且连接池未使用同步锁(如threading.Lock)阻塞异步操作。若使用了锁,需替换为asyncio的asyncio.Lock。

前端代码验证

你的前端WebSocket逻辑无明显问题,无需修改。只要后端事件循环恢复正常调度,前端就能实时接收进度消息。

内容的提问来源于stack exchange,提问作者Harmony

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 19:23:16