Event streaming is a way of processing data as a continuous flow of events rather than as one-time requests. Each event represents something that happened (e.g., “user signed up”, “order placed”), and systems can react to these events in real time or near real time. Event streaming enables systems to publish, consume, store, and process events continuously and asynchronously, making it well suited for real-time features such as notifications, dashboards, and live updates.
Pub/Sub Model
The pub/sub model is a messaging pattern where publishers send messages and subscribers (clients) receive them. Redis provides such mechanism using channels, where messages published to a channel are delivered to all active subscribers.
Messages in Redis pub/sub are not persisted, meaning that if a subscriber is offline, it will miss any messages published during that time. There is also no built-in replay support. Despite these limitations, Redis pub/sub is extremely efficient and well suited for real-time notifications, such as chat systems or live status updates.
Streaming API (View)
In this post we will implement a Django Server-Sent Events (SSE) endpoint that streams messages from a Redis pub/sub channel to connected clients in real-time.
The stream_events view subscribes to the demo_stream Redis channel and continuously listens for new messages. Whenever a message arrives, it is yielded as an SSE-formatted response using Django’s StreamingHttpResponse.
import redis
from django.http import StreamingHttpResponse
import time
def stream_events(request):
r = redis.Redis(host="redis", port=6379, db=0)
pubsub = r.pubsub()
pubsub.subscribe("demo_stream")
def event_stream():
try:
print("connected")
while True:
message = pubsub.get_message(timeout=1)
if message and message["type"] == "message":
data = message["data"].decode("utf-8")
print(data)
yield f"data: {data}\n\n"
time.sleep(0.01)
except GeneratorExit:
# Client disconnected
pass
finally:
pubsub.close()
response = StreamingHttpResponse(
event_stream(), content_type="text/event-stream")
response['Cache-Control'] = 'no-cache'
return response
This implementation keeps the HTTP connection open and continuously pushes updates to the client whenever new messages are published to Redis.
Publishing Messages
Messages can be published to Redis using redis-cli or a Python Redis client, and any client visiting /stream/ will receive them live.
From the Redis CLI running inside Docker, messages can be published with
docker exec -it redis redis-cli publish demo_stream "Test Event"
while from the Python Redis client, a sample example looks like this:
import redis, time
r = redis.Redis(host="127.0.0.1", port=6379, db=0)
for i in range(5):
msg = f"Message #{i}"
r.publish("demo_stream", msg)
print("Published:", msg)
time.sleep(1)
Each published message is immediately pushed to all connected SSE clients.
Accessing the Stream
The streaming url is
path('stream/', stream_events, name="stream")
When visiting /stream/ in the browser (or via a compatible client), any published messages will appear in real time, as long as the client remains connected.
Note on Sync vs Async
This view runs in synchronous mode. If the Django application is running under an async server (like Daphne or Uvicorn), then a synchronous streaming view that uses blocking operations may block the event loop. This can cause the entire application to become unresponsive. To avoid this, make sure that either:
-
the whole application runs in synchronous mode, or
-
the view is rewritten to be fully async and non-blocking.