
Real-time em dashboards: WebSockets, SSE ou polling
Imagine um dashboard de operações logísticas que mostra o status das entregas em tempo real. Um gestor está monitorando a operação e vê que todas as rotas estão no prazo. Na verdade, quatro rotas atrasaram há 12 minutos — mas o dashboard só atualiza a cada 15 minutos. Ele não intervém porque não vê o problema. As entregas atrasam. O cliente reclama.
Dados estáticos em dashboards de operações não são apenas inconvenientes — eles causam decisões erradas baseadas em informações defasadas. A questão não é se implementar real-time, mas qual mecanismo usar para cada cenário.
Polling: Simples mas Custoso em Escala
Polling é a abordagem mais simples: o cliente faz uma requisição HTTP a cada N segundos perguntando "tem novidade?". Toda a infraestrutura existente funciona sem modificação — load balancers, caches, autenticação.
// hooks/usePolling.ts
import { useEffect, useRef, useCallback } from 'react';
interface UsePollingOptions {
interval: number; // ms
enabled?: boolean;
}
export function usePolling(
fetchFn: () => Promise<void>,
{ interval, enabled = true }: UsePollingOptions
) {
const timeoutRef = useRef<NodeJS.Timeout>();
const fetchRef = useRef(fetchFn);
fetchRef.current = fetchFn;
const schedule = useCallback(() => {
timeoutRef.current = setTimeout(async () => {
if (enabled) {
await fetchRef.current();
schedule(); // reagenda apenas após a resposta, evita overlap
}
}, interval);
}, [interval, enabled]);
useEffect(() => {
if (enabled) {
schedule();
}
return () => clearTimeout(timeoutRef.current);
}, [enabled, schedule]);
}
// Uso:
usePolling(async () => {
const data = await fetchDashboardMetrics();
setMetrics(data);
}, { interval: 30_000, enabled: isVisible }); // 30s, só quando aba está ativa
O problema do polling aparece na escala. Com 500 usuários simultâneos e polling a cada 30 segundos, você tem ~17 requisições por segundo constantes para o backend — independentemente de haver dados novos. Com 5.000 usuários, são ~167 req/s de "polling vacuo" que consomem recursos sem entregar valor.
Polling inteligente mitiga isso: exponential backoff quando não há dados novos, polling desativado quando a aba não está visível (via Page Visibility API), e cache no cliente para evitar re-renderizações desnecessárias.
Use polling quando: intervalos de atualização de 30s+ são aceitáveis, o número de clientes simultâneos é pequeno (< 500), a infraestrutura não suporta conexões persistentes, ou você está em ambiente serverless onde conexões longas são inviáveis.
Server-Sent Events: Unidirecional e Leve
SSE (Server-Sent Events) é um protocolo HTTP onde o servidor mantém uma conexão aberta e envia eventos ao cliente quando há novidades. O cliente só recebe — não envia dados pela mesma conexão.
Para dashboards, SSE é frequentemente a melhor escolha: a comunicação é quase sempre unidirecional (servidor → cliente), o protocolo é simples, reconexão automática está embutida no browser, e funciona sobre HTTP/2 sem modificações de infraestrutura.
// app/api/metrics/stream/route.ts (Next.js App Router)
export async function GET(request: Request) {
const encoder = new TextEncoder();
const stream = new ReadableStream({
async start(controller) {
const sendEvent = (event: string, data: unknown) => {
const payload = `event: ${event}\ndata: ${JSON.stringify(data)}\n\n`;
controller.enqueue(encoder.encode(payload));
};
// Envia snapshot inicial
const initial = await fetchCurrentMetrics();
sendEvent('snapshot', initial);
// Assina mudanças no banco (ex: Postgres LISTEN/NOTIFY)
const subscription = db.metrics.subscribe(async (change) => {
sendEvent('update', change);
});
// Heartbeat para manter conexão viva através de proxies
const heartbeat = setInterval(() => {
controller.enqueue(encoder.encode(': heartbeat\n\n'));
}, 30_000);
request.signal.addEventListener('abort', () => {
subscription.unsubscribe();
clearInterval(heartbeat);
controller.close();
});
}
});
return new Response(stream, {
headers: {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
}
});
}
// hooks/useSSE.ts (cliente)
export function useSSE<T>(url: string) {
const [data, setData] = useState<T | null>(null);
useEffect(() => {
const es = new EventSource(url);
es.addEventListener('snapshot', (e) => {
setData(JSON.parse(e.data));
});
es.addEventListener('update', (e) => {
const update = JSON.parse(e.data);
setData(prev => mergeUpdate(prev, update));
});
es.onerror = () => {
// EventSource reconecta automaticamente após erro
};
return () => es.close();
}, [url]);
return data;
}
Limitação do SSE: cada conexão mantém um socket aberto no servidor. Em plataformas serverless (Vercel Edge Functions, Cloudflare Workers), isso tem restrições de tempo de execução. Para escala maior, você precisa de um servidor dedicado ou de um serviço gerenciado (Ably, Pusher, Supabase Realtime).
Use SSE quando: atualizações são server → client apenas, você precisa de latência baixa (< 1s), o ambiente suporta conexões HTTP longas, e o número de conexões simultâneas está dentro da capacidade do servidor.
WebSockets: Bidirecional para Dashboards Colaborativos
WebSockets estabelecem uma conexão TCP bidirecional persistente. O cliente pode enviar dados ao servidor e receber dados do servidor pela mesma conexão, com latência mínima.
Para a maioria dos dashboards de visualização, WebSockets são over-engineering — SSE ou polling são suficientes. WebSockets fazem sentido quando o dashboard tem elementos colaborativos: múltiplos usuários editando filtros compartilhados, cursores em tempo real, comentários em células de dados, ou notificações de que outro usuário acabou de exportar o relatório que você está vendo.
| Critério | Polling | SSE | WebSockets |
|---|---|---|---|
| Direção | Req/Res | Server → Client | Bidirecional |
| Latência | Alta (= intervalo) | Baixa (< 1s) | Muito baixa (< 100ms) |
| Complexidade de infra | Nenhuma | Baixa | Média-alta |
| Serverless compatível | Sim | Limitado | Não |
| Reconexão automática | Manual | Nativa | Manual |
| Escala (clientes simultâneos) | Alta | Média | Baixa sem infra adicional |
| Ideal para | Relatórios, ETAs longos | Monitoring, alertas | Colaboração, trading |
Escolhendo por Frequência de Atualização e Número de Clientes
A decisão prática combina dois eixos: frequência de atualização necessária e número esperado de clientes simultâneos.
- Atualização a cada 5+ minutos + qualquer escala: polling com cache no cliente. Simples, resiliente, funciona em qualquer infra.
- Atualização a cada 5-60s + até 2.000 clientes: SSE com servidor dedicado ou Supabase Realtime.
- Atualização < 5s + até 500 clientes: SSE ou WebSockets dependendo se há comunicação bidirecional.
- Atualização < 1s + escala maior: serviço gerenciado de WebSockets (Ably, Pusher) ou arquitetura com Redis pub/sub + WebSocket server separado.
Uma otimização frequentemente negligenciada: atualizar apenas os componentes que mudaram, não o dashboard inteiro. Se apenas o KPI de "pedidos em andamento" mudou, re-renderizar os 12 gráficos do dashboard é desperdício. O modelo de eventos snapshot + update descrito no exemplo SSE resolve isso — o update contém apenas o delta, e o cliente faz merge.
Conclusão
Real-time em dashboards é um espectro, não uma decisão binária. Polling bem implementado com visibilidade de aba e exponential backoff resolve a maioria dos casos de dashboards executivos e de relatório. SSE é o ponto ideal para dashboards operacionais com dados que mudam frequentemente. WebSockets ficam reservados para dashboards verdadeiramente colaborativos ou de trading onde cada segundo importa.
O erro mais caro é implementar WebSockets "porque é moderno" em um contexto onde polling de 30 segundos seria perfeitamente adequado — a complexidade adicional de infraestrutura raramente se justifica.
Na SystemForge, a estratégia de real-time é definida durante o design técnico do sistema, junto com a arquitetura de backend e as decisões de escala. Partir de um HLD que documenta explicitamente a escolha de mecanismo de real-time — e por quê — evita reescritas quando o sistema cresce.
Precisa de um Dashboard B2B?
Construímos dashboards analíticos e painéis de gestão sob medida.
Saiba mais →Precisa de ajuda?

