Building real-time event streams at sub-50ms
A deep dive into our WebSocket architecture, back-pressure handling, and how we achieve consistent low latency.
Why latency matters for access control
When someone badges into a building, the dashboard operator needs to see it immediately — not in 2 seconds, not in 500 milliseconds. In security, stale data is dangerous data.
We set ourselves a target: every door event must appear on every connected dashboard in under 50 milliseconds, end-to-end. Here’s how we got there.
The architecture
Our event pipeline has three stages:
Stage 1: Controller to cloud. Controllers maintain persistent TCP connections to our edge. When a door event occurs, the controller pushes a binary-encoded event packet. Average transit time: 8-12ms.
Stage 2: Processing. The event hits our event processor, which enriches it with employee data, applies policy rules, and checks for anomalies. This runs in-memory with pre-loaded caches. Average processing time: 3-5ms.
Stage 3: Fan-out. Processed events are broadcast to all connected WebSocket clients via our pub/sub layer. We use per-organization channels to avoid broadcasting irrelevant events. Average fan-out time: 2-4ms.
Back-pressure handling
The hardest part wasn’t speed — it was consistency. When a site has 200 doors and a shift change triggers 500 events in 10 seconds, you need back-pressure that degrades gracefully without dropping events.
Our solution: a ring buffer per client connection with adaptive batch sizing. When a client falls behind, we batch events together rather than queuing unboundedly. The client always gets every event, but during bursts they arrive in micro-batches of 3-5 instead of individually.
The numbers
P50 latency: 23ms. P95: 41ms. P99: 48ms. Measured across all production traffic over 30 days.