https://github.com/vvanglro/resumable-sse
Asynchronous recoverable SSE (Server-Sent Events) push toolkit, supporting Redis and in-memory backend.
https://github.com/vvanglro/resumable-sse
fastapi sse
Last synced: about 1 month ago
JSON representation
Asynchronous recoverable SSE (Server-Sent Events) push toolkit, supporting Redis and in-memory backend.
- Host: GitHub
- URL: https://github.com/vvanglro/resumable-sse
- Owner: vvanglro
- License: mit
- Created: 2025-07-11T14:13:11.000Z (12 months ago)
- Default Branch: main
- Last Pushed: 2025-07-22T08:55:30.000Z (11 months ago)
- Last Synced: 2025-07-22T10:42:45.900Z (11 months ago)
- Topics: fastapi, sse
- Language: Python
- Homepage: https://github.com/vvanglro/resumable-sse
- Size: 25.4 KB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# resumable-sse
> Asynchronous recoverable SSE (Server-Sent Events) push toolkit, supporting Redis and in-memory backend.
## β¨ Features
* β
Seamless integration with async generators (`async for`)
* π Resumable message stream support with `Last-Event-ID`
* πΎ Backend-agnostic: in-memory or Redis support
* βοΈ Clean abstraction, minimal API surface
* π§ͺ Easy to test, extendable for custom storage backends
## π€ Why Use `resumable-sse`?
In AI chat or streaming applications, when a user refreshes the page or the network is interrupted, the ongoing Server-Sent Events (SSE) stream is lost. Without a recovery mechanism, the frontend has no way to continue receiving the previous stream, and the backend often has to **re-generate the entire response**, wasting time and compute.
`resumable-sse` solves this by:
* Caching every message chunk in a backend (in-memory or Redis)
* Allowing clients to resume streaming from the last received event via `Last-Event-ID`
* Decoupling message generation from delivery, so you donβt have to re-trigger expensive operations
### π§ Use case example:
Youβre building a web AI assistant. A user asks a long question. Halfway through the response, they accidentally refresh the browser. Instead of restarting the whole LLM generation, the backend resumes from where it left off and continues streaming seamlessly.
This avoids:
* Unnecessary re-generation
* Cost and latency from repeated model computation
* Poor user experience
## π¦ Installation
```bash
pip install resumable-sse
```
Or from source:
```bash
git clone https://github.com/vvanglro/resumable-sse.git
cd resumable-sse
pip install -e .
```
## π Quick Start
Using with FastAPI:
```python
import asyncio
from fastapi import FastAPI, Request
from sse_starlette.sse import EventSourceResponse
from resumable_sse.factory import get_streamer
app = FastAPI()
streamer = get_streamer(backend="memory")
async def fake_generator():
for word in ["Hello,", "I'm an AI.", "Nice to meet you."]:
yield word
await asyncio.sleep(1)
@app.get("/stream")
async def stream(request: Request, session_id: str):
return EventSourceResponse(
streamer.stream(session_id=session_id, generator=fake_generator())
)
```
Supports resume with:
```http
GET /stream?session_id=abc
```
## π Redis Backend Example
```python
import redis.asyncio as redis
from resumable_sse.factory import get_streamer
redis_client = redis.Redis()
streamer = get_streamer(backend="redis", redis_client=redis_client)
```
## π API Reference
```python
async def stream(
self,
session_id: str,
generator: ContentStream,
last_id: str = "0",
) -> AsyncGenerator[dict, None]:
```
* `session_id`: Unique ID per conversation or stream session
* `last_id`: Resume position (used with `Last-Event-ID`)
* `generator`: Async generator function that yields message chunks
## π§ͺ Run Tests
```bash
pytest tests/
```
## π Project Structure
```
resumable_sse/
βββ base.py # Abstract base class
βββ memory.py # In-memory implementation
βββ redis.py # Redis implementation
βββ factory.py # Factory for backend selection
βββ __init__.py
README.md
pyproject.toml
```
## π License
MIT License
---