Files
agent_alpha/backend/services/rag_status.py
T
furyhawk bb4b614711 feat: Implement RAG document and sync services with vector store integration
- Added `vectorstore.py` for managing vector storage operations using Milvus.
- Introduced `rag_document.py` for handling RAG document lifecycle, including ingestion and status updates.
- Created `rag_status.py` for streaming RAG ingestion status via Redis pub/sub.
- Developed `rag_sync.py` for managing synchronization operations and logs.
- Implemented `sync_source.py` for managing sync source configurations and triggering syncs.
- Established a lightweight task dispatcher in `dispatcher.py` for background task execution.
- Registered task functions for RAG ingestion and sync operations in `rag_tasks.py`.
- Configured task dispatcher settings in `arq_settings.py`.
- Added necessary database models and schemas for RAG document and sync operations.
2026-06-13 21:52:27 +08:00

50 lines
1.7 KiB
Python

"""RAG status streaming — Redis pub/sub fan-out for SSE clients."""
import asyncio
import logging
from collections.abc import AsyncIterator
import redis.asyncio as aioredis
from fastapi.sse import ServerSentEvent
from backend.core.config import settings
logger = logging.getLogger(__name__)
class RAGStatusService:
"""Streams RAG ingestion status events from Redis pub/sub."""
CHANNEL = "rag_status"
async def stream_events(self) -> AsyncIterator[ServerSentEvent]:
"""Yield ``ServerSentEvent`` items as they arrive on the ``rag_status`` channel.
The Redis client is created per-stream (one connection per subscriber). Cleanup is
guaranteed via ``finally`` even if the consumer disconnects mid-stream.
"""
client = aioredis.from_url(settings.valkey_url) # type: ignore[no-untyped-call]
pubsub = client.pubsub()
await pubsub.subscribe(self.CHANNEL)
event_id = 0
try:
async for message in pubsub.listen():
if message["type"] != "message":
continue
payload = message["data"]
data = payload.decode() if isinstance(payload, bytes) else payload
event_id += 1
yield ServerSentEvent(raw_data=data, event="status", id=str(event_id))
except asyncio.CancelledError:
# Client disconnected — propagate cancellation cleanly
raise
except Exception as exc:
logger.warning("RAG SSE stream error: %s", exc)
finally:
try:
await pubsub.unsubscribe(self.CHANNEL)
await client.aclose()
except Exception as exc:
logger.debug("RAG SSE cleanup error: %s", exc)