Problem
The lint and index WebSocket endpoints (lint/ws, ontology/index-ws) both subscribe to a single shared Redis channel (lint:updates, ontology_index:updates). Every connected client receives every message and filters by project_id in Python:
data = json.loads(message["data"])
if data.get("project_id") == project_id_str:
await websocket.send_json(data)
With many concurrent connections, every client processes every message even if it's for a different project. This is fine at small scale but becomes wasteful at thousands of concurrent connections.
Proposed optimization
Use per-project Redis channels instead of a single global channel:
# Worker publishes to:
channel = f"lint:updates:{project_id}"
# WebSocket subscribes to:
await pubsub.subscribe(f"lint:updates:{project_id}")
This way each client only receives messages relevant to its project, eliminating the filtering overhead.
Changes needed
Worker (worker.py):
- Publish to
f"lint:updates:{project_id}" and f"ontology_index:updates:{project_id}" instead of the global channels
WebSocket endpoints (lint.py, projects.py):
- Subscribe to
f"{CHANNEL}:{project_id}" instead of the global channel
- Remove the
if data.get("project_id") == project_id_str filter (no longer needed)
Scope
This is a low-priority optimization. The current approach works correctly and performs well for hundreds of projects. Consider implementing when:
- Concurrent WebSocket connections regularly exceed ~1000
- Redis pubsub message volume becomes measurable overhead
🤖 Generated with Claude Code
Problem
The lint and index WebSocket endpoints (
lint/ws,ontology/index-ws) both subscribe to a single shared Redis channel (lint:updates,ontology_index:updates). Every connected client receives every message and filters byproject_idin Python:With many concurrent connections, every client processes every message even if it's for a different project. This is fine at small scale but becomes wasteful at thousands of concurrent connections.
Proposed optimization
Use per-project Redis channels instead of a single global channel:
This way each client only receives messages relevant to its project, eliminating the filtering overhead.
Changes needed
Worker (
worker.py):f"lint:updates:{project_id}"andf"ontology_index:updates:{project_id}"instead of the global channelsWebSocket endpoints (
lint.py,projects.py):f"{CHANNEL}:{project_id}"instead of the global channelif data.get("project_id") == project_id_strfilter (no longer needed)Scope
This is a low-priority optimization. The current approach works correctly and performs well for hundreds of projects. Consider implementing when:
🤖 Generated with Claude Code