SSE-Starlette
sse-starlette is a production-ready Python library that provides a Server-Sent Events (SSE) plugin for Starlette and FastAPI frameworks. It offers a standards-compliant implementation of the W3C SSE specification, including features like automatic client disconnect detection, graceful shutdown, and thread-safe event management. The current version is 3.3.3, and the library maintains an active release cadence with regular updates and dependency management.
Warnings
- gotcha SSE streaming does not work in combination with Starlette's GZipMiddleware. Applying GZipMiddleware to an SSE endpoint will buffer the response, preventing real-time delivery.
- gotcha Reverse proxies (e.g., Nginx, Apache, Cloudflare, Akamai, HAProxy) often buffer responses by default, which can break the real-time nature of SSE. This can cause events to be delayed or batched.
- breaking Prior to v3.2.0, handling graceful shutdown of SSE streams could be problematic, often leading to 'Waiting for background tasks to complete' warnings or immediate force-cancellation of generators upon server termination. This prevented proper cleanup or sending final events.
- gotcha Versions prior to v3.1.2 had a 'watcher task leak' due to incorrect `threading.local` usage, potentially leading to resource exhaustion or unexpected behavior in long-running applications.
- gotcha When using database sessions (e.g., SQLAlchemy's `AsyncSession`) or other non-thread-safe objects within SSE generators, care must be taken to avoid passing them directly. The streaming internally uses `anyio.TaskGroups`, which can lead to thread-safety issues.
Install
-
pip install sse-starlette
Imports
- EventSourceResponse
from sse_starlette import EventSourceResponse
- ServerSentEvent
from sse_starlette import ServerSentEvent
- JSONServerSentEvent
from sse_starlette import JSONServerSentEvent
Quickstart
import asyncio
from starlette.applications import Starlette
from starlette.routing import Route
from sse_starlette import EventSourceResponse
async def generate_events():
for i in range(10):
yield {"data": f"Event {i}"}
await asyncio.sleep(1)
async def sse_endpoint(request):
return EventSourceResponse(generate_events())
app = Starlette(routes=[Route("/events", sse_endpoint)])
# To run this example, you would typically use an ASGI server like uvicorn:
# uvicorn your_module_name:app --reload