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
相关产品推荐
相关产品推荐

