feat(api): remove outdated planning document and implement streaming service for real-time task updates

This commit is contained in:
Davidson Gomes
2025-04-29 20:35:33 -03:00
parent 34734b6da7
commit 690168fa5d
7 changed files with 793 additions and 225 deletions

70
src/utils/streaming.py Normal file
View File

@@ -0,0 +1,70 @@
import asyncio
from typing import AsyncGenerator, Optional
from fastapi import HTTPException
class SSEUtils:
@staticmethod
async def with_timeout(
generator: AsyncGenerator, timeout: int = 30, retry_attempts: int = 3
) -> AsyncGenerator:
"""
Adiciona timeout e retry a um gerador de eventos SSE.
Args:
generator: Gerador de eventos
timeout: Tempo máximo de espera em segundos
retry_attempts: Número de tentativas de reconexão
Yields:
Eventos do gerador
"""
attempts = 0
while attempts < retry_attempts:
try:
async for event in asyncio.wait_for(generator, timeout):
yield event
break
except asyncio.TimeoutError:
attempts += 1
if attempts >= retry_attempts:
raise HTTPException(
status_code=408, detail="Timeout após múltiplas tentativas"
)
await asyncio.sleep(1) # Espera antes de tentar novamente
@staticmethod
def format_error_event(error: Exception) -> str:
"""
Formata um evento de erro SSE.
Args:
error: Exceção ocorrida
Returns:
String formatada do evento SSE
"""
return f"event: error\ndata: {str(error)}\n\n"
@staticmethod
def validate_sse_headers(headers: dict) -> None:
"""
Valida headers necessários para SSE.
Args:
headers: Dicionário de headers
Raises:
HTTPException se headers inválidos
"""
required_headers = {
"Accept": "text/event-stream",
"Cache-Control": "no-cache",
"Connection": "keep-alive",
}
for header, value in required_headers.items():
if headers.get(header) != value:
raise HTTPException(
status_code=400, detail=f"Header {header} inválido ou ausente"
)