kangda-robot-backend/ruoyi-fastapi-backend/test_sse_buffer_test.py
2025-12-17 14:28:51 +08:00

170 lines
5.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""
SSE流式响应缓冲测试脚本
用于验证FastAPI StreamingResponse的缓冲机制不修改现有代码
"""
import asyncio
import time
import json
from typing import AsyncGenerator
from fastapi import FastAPI, Response
from fastapi.responses import StreamingResponse
import uvicorn
app = FastAPI()
async def slow_data_generator() -> AsyncGenerator[dict, None]:
"""模拟慢速数据生成类似于RAGFlow的流式响应"""
print("Generator started at:", time.time())
for i in range(5):
print(f"Generating chunk {i} at {time.time()}")
data = {
"data": {
"answer": f"这是第{i+1}个数据块,生成时间: {time.time()}",
"timestamp": time.time()
}
}
yield data
await asyncio.sleep(1) # 模拟每1秒产生一个数据块
print(f"Yielded chunk {i} at {time.time()}")
@app.get("/test/streaming")
async def test_streaming():
"""测试1: FastAPI StreamingResponse的默认行为"""
start_time = time.time()
async def stream_response():
print(f"Stream response started at {start_time}")
async for chunk in slow_data_generator():
print(f"About to yield: {chunk}")
payload = json.dumps(chunk, ensure_ascii=False)
sse_data = f"data: {payload}\n\n"
print(f"Yielding SSE data at {time.time()}")
yield sse_data
print(f"Stream response ended at {time.time()}")
return StreamingResponse(
stream_response(),
media_type='text/event-stream',
headers={
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'X-Accel-Buffering': 'no'
}
)
@app.get("/test/plain")
async def test_plain():
"""测试2: 对比使用PlainTextResponse的行为"""
async def generate_text():
async for chunk in slow_data_generator():
payload = json.dumps(chunk, ensure_ascii=False)
sse_data = f"data: {payload}\n\n"
yield sse_data
await asyncio.sleep(0.1) # 短暂延迟
return Response(generate_text(), media_type='text/plain')
@app.get("/test/flush")
async def test_flush():
"""测试3: 尝试强制刷新缓冲区"""
async def stream_with_flush():
async for chunk in slow_data_generator():
payload = json.dumps(chunk, ensure_ascii=False)
sse_data = f"data: {payload}\n\n"
# 尝试多种方法强制刷新
print(f"Yielding with flush attempt: {chunk}")
yield sse_data
# 让出控制权
await asyncio.sleep(0)
return StreamingResponse(
stream_with_flush(),
media_type='text/event-stream'
)
# 客户端测试脚本
async def test_client():
"""客户端测试函数,用于验证服务端响应行为"""
print("=" * 50)
print("SSE流式响应缓冲测试")
print("=" * 50)
import aiohttp
async with aiohttp.ClientSession() as session:
# 测试1: StreamingResponse
print("\n📡 测试1: FastAPI StreamingResponse")
print("请求URL: http://localhost:8000/test/streaming")
try:
async with session.get('http://localhost:8000/test/streaming') as response:
print(f"响应状态: {response.status}")
print(f"响应头: {dict(response.headers)}")
chunk_count = 0
async for line in response.content:
chunk_count += 1
print(f"客户端收到数据 {chunk_count}: {line.decode().strip()} | 时间: {time.time()}")
except Exception as e:
print(f"测试1失败: {e}")
await asyncio.sleep(2)
# 测试2: PlainTextResponse
print("\n📡 测试2: PlainTextResponse")
print("请求URL: http://localhost:8000/test/plain")
try:
async with session.get('http://localhost:8000/test/plain') as response:
print(f"响应状态: {response.status}")
chunk_count = 0
async for line in response.content:
chunk_count += 1
print(f"客户端收到数据 {chunk_count}: {line.decode().strip()} | 时间: {time.time()}")
except Exception as e:
print(f"测试2失败: {e}")
if __name__ == "__main__":
print("""
SSE流式响应缓冲测试脚本
这个脚本会启动一个测试服务器模拟RAGFlow的流式响应行为
用于验证FastAPI StreamingResponse是否存在缓冲问题。
使用方法:
1. 启动测试服务器: python test_sse_buffer_test.py server
2. 在另一个终端运行客户端测试: python test_sse_buffer_test.py client
或者直接运行主程序进行集成测试
""")
import sys
if len(sys.argv) > 1:
if sys.argv[1] == "server":
print("启动测试服务器...")
uvicorn.run(app, host="0.0.0.0", port=8000, log_level="info")
elif sys.argv[1] == "client":
print("运行客户端测试...")
asyncio.run(test_client())
else:
print("运行集成测试...")
print("请在另一个终端运行 'python test_sse_buffer_test.py client' 来测试")