Real-Time in a Multi-Region Video Platform
When a viral news clip appears in the UAE or a Danish documentary breaks into Nordic trending charts, TrendVidStream users should see it instantly. A Python WebSocket server bridges the gap between the PHP cron fetcher and the browser.
Architecture
PHP Cron Fetcher ──→ Redis Pub/Sub ──→ Python WS Server ──→ Browser clients
(8 regions) (one channel per region) (filtered by locale)
Python WebSocket Server
pip install websockets redis asyncio
import asyncio
import json
import logging
import urllib.parse
import redis.asyncio as aioredis
import websockets
from websockets.server import WebSocketServerProtocol
logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO)
region_clients: dict[str, set[WebSocketServerProtocol]] = {}
async def broadcast_to_region(region: str, message: str) -> None:
clients = region_clients.get(region, set())
if not clients:
return
dead = set()
results = await asyncio.gather(
*(ws.send(message) for ws in clients), return_exceptions=True,
)
for ws, result in zip(list(clients), results):
if isinstance(result, Exception):
dead.add(ws)
clients.difference_update(dead)
async def handler(websocket: WebSocketServerProtocol) -> None:
qs = urllib.parse.parse_qs(urllib.parse.urlparse(websocket.path).query)
region = qs.get('region', ['US'])[0].upper()
region_clients.setdefault(region, set()).add(websocket)
try:
await websocket.wait_closed()
finally:
region_clients.get(region, set()).discard(websocket)
async def redis_subscriber() -> None:
client = aioredis.from_url('redis://localhost:6379', decode_responses=True)
pubsub = client.pubsub()
channels = ['tvs:AE', 'tvs:FI', 'tvs:CZ', 'tvs:DK', 'tvs:BE', 'tvs:GB', 'tvs:CH', 'tvs:US']
await pubsub.subscribe(*channels)
async for msg in pubsub.listen():
if msg['type'] != 'message':
continue
region = msg['channel'].split(':')[1]
try:
payload = json.loads(msg['data'])
out = json.dumps(payload, ensure_ascii=False)
await broadcast_to_region(region, out)
except (json.JSONDecodeError, KeyError) as e:
logger.warning(f'Bad payload: {e}')
async def main() -> None:
server = await websockets.serve(handler, '0.0.0.0', 8765)
await asyncio.gather(server.wait_closed(), redis_subscriber())
if __name__ == '__main__':
asyncio.run(main())
PHP Publisher with RTL Metadata
<?php
declare(strict_types=1);
class NotificationPublisher
{
private \Redis $redis;
public function __construct()
{
$this->redis = new \Redis();
$this->redis->connect('127.0.0.1', 6379);
}
public function publish(array $video, string $region): void
{
$payload = json_encode([
'event' => 'new_trending',
'region' => $region,
'video_id' => $video['video_id'],
'title' => $video['title'],
'thumbnail' => $video['thumbnail_url'],
'channel' => $video['channel_title'],
'rtl' => in_array($region, ['AE', 'IL'], true),
'ts' => time(),
], JSON_UNESCAPED_UNICODE);
$this->redis->publish("tvs:{$region}", $payload);
}
}
Browser Client with RTL Toast
class TrendingNotifier {
constructor(region = 'AE') {
this.ws = new WebSocket(`wss://ws.trendvidstream.com/?region=${region}`);
this.ws.onmessage = (e) => {
const data = JSON.parse(e.data);
if (data.event === 'new_trending') this.showToast(data);
};
}
showToast(video) {
const toast = document.createElement('div');
toast.className = 'trending-toast';
if (video.rtl) toast.setAttribute('dir', 'rtl');
toast.innerHTML = `<img src="${video.thumbnail}" alt=""><div><strong>Trending in ${video.region}</strong><span>${video.title}</span></div>`;
document.body.appendChild(toast);
setTimeout(() => toast.remove(), 5000);
}
}
new TrendingNotifier(currentUserRegion);
Multi-Region Considerations
TrendVidStream spans UAE (Arabic RTL), Czech Republic (diacritics: č, ž, š), Finland (ä, ö), and Denmark (ø, å). Key points:
-
Arabic RTL: send
rtl: truein the payload so the browser can applydir="rtl"dynamically. -
JSON encoding: always
JSON_UNESCAPED_UNICODEin PHP andensure_ascii=Falsein Python so diacritics and Arabic glyphs transmit unmangled. - Connection per region: routing clients into per-region sets means a viral clip in Finland only wakes Finnish clients, not UAE users.
This article is part of the Building TrendVidStream series. Check out TrendVidStream to see these techniques in action.
Top comments (0)