Tarek.
← All projects

2025

Pulseboard

A realtime status dashboard that streams uptime and latency for a fleet of services — sub-second updates over WebSockets.

ReactGoWebSocketsRedisClickHouse

The problem

Our team's status page updated every five minutes via polling, which meant incidents were discovered by users before they were discovered by us. Worse, the poll endpoint was itself a bottleneck during traffic spikes — exactly when we needed it most.

Pulseboard is what came out of a two-week hack-week project that turned into production infrastructure: a realtime view of uptime, p95 latency and error rates across ~40 services.

Approach

The pipeline

Probes run every 10 seconds from three regions. Results flow through Redis Streams into ClickHouse for storage, with a thin Go fan-out service broadcasting deltas to connected browsers:

hub/hub.go
func (h *Hub) broadcast(msg ProbeResult) {
    h.mu.RLock()
    defer h.mu.RUnlock()
 
    for client := range h.clients {
        select {
        case client.send <- msg:
        default:
            // Slow consumer — drop frame rather than block the hub.
            go h.evict(client)
        }
    }
}

The non-blocking send matters: one slow tab on a hotel Wi-Fi must never stall updates for everyone else.

Rendering at 60 updates per minute

Browsers re-rendering a large table once per second will melt. Two techniques keep it smooth:

  1. Coalescing — the client batches incoming results and flushes at animation-frame cadence.
  2. Row virtualization — only visible rows exist in the DOM.
components/live-grid.tsx
const pending = useRef<ProbeResult[]>([]);
 
useEffect(() => {
  socket.on("probe", (result) => pending.current.push(result));
  let raf: number;
  const flush = () => {
    if (pending.current.length) {
      applyResults(splice(pending.current));
      pending.current = [];
    }
    raf = requestAnimationFrame(flush);
  };
  raf = requestAnimationFrame(flush);
  return () => cancelAnimationFrame(raf);
}, []);

Backpressure as a product feature

When a browser falls behind (tab backgrounded for an hour), it doesn't replay an hour of events — it requests a snapshot of current state plus the last incident timeline. Simpler, faster, and honestly all anyone wants after being away.

Outcome

  • Time-to-detect dropped from ~5 minutes to under 15 seconds
  • Sustained 3k concurrent connections on a single small Go instance
  • The polling status page was retired entirely

What I learned

  • Design for the slowest subscriber first. Backpressure handling was the hardest part and the most valuable.
  • ClickHouse + Redis Streams is a genuinely great stack for time-series dashboards without running Kafka.
  • Realtime UX is mostly about update discipline, not socket plumbing.