June 21, 2025
Server-Sent Events (SSE): Reatividade Simples e Eficiente no Frontend
Como usar Server-Sent Events em microfrontends para fluxos de dados unidirecionais, notificações em tempo real, feature flags dinâmicas e comunicação entre Shell e MFEs.

O Server-Sent Events (SSE) continua sendo uma opção sólida para fluxos de dados unidirecionais no frontend — especialmente em contextos modernos de Micro Frontends (MFEs), onde simplicidade, performance e escalabilidade são essenciais.
Hoje, o SSE vem sendo utilizado em combinações como:
- Shells orquestradores (Single-SPA, Module Federation, Zephyr)
- Feature Flags dinâmicas baseadas em AI
- Edge Functions (Cloudflare Workers, Vercel Functions)
- Streams de eventos (Redis Streams, Kafka, RabbitMQ)
✅ Vantagens do SSE no Cenário Atual
Simplicidade e Compatibilidade
- ✅ Baseado em HTTP — sem handshakes adicionais
- ✅ Compatível com infraestruturas modernas (HTTP/2, CDN, Serverless)
- ✅ Código leve, sem dependências externas
- ✅ Reconexão automática nativa (EventSource)
Performance e Escalabilidade
- ✅ Ideal para notificações, logs, atualizações contextuais
- ✅ Baixo overhead de conexão
- ✅ Suporte nativo a HTTP/2 multiplexing
- ✅ Cache-friendly com CDNs
🏗️ Aplicações em Arquiteturas de Micro Frontends
Em estruturas com MFEs desacoplados, o SSE pode ser mantido no Shell e os eventos propagados aos MFEs por meio de CustomEvent, mantendo o isolamento dos times e a reatividade em tempo real.
Exemplo com Single-SPA:
// Shell (root-app)
const source = new EventSource('/api/sse');
source.onmessage = ({ data }) => {
const event = JSON.parse(data);
window.dispatchEvent(new CustomEvent('sse:event', { detail: event }));
};
// MFE (qualquer framework)
useEffect(() => {
const handler = (e) => handleIncomingData(e.detail);
window.addEventListener('sse:event', handler);
return () => window.removeEventListener('sse:event', handler);
}, []);
🎯 Exemplos de Uso Práticos
1. Atualização em Tempo Real de Feature Flags
// Shell - Feature Flags dinâmicas
const featureFlagsSource = new EventSource('/api/feature-flags/sse');
featureFlagsSource.onmessage = ({ data }) => {
const flags = JSON.parse(data);
// Broadcast para todos os MFEs
window.dispatchEvent(new CustomEvent('feature-flags:update', {
detail: flags
}));
};
// MFE - Consumir feature flags
useEffect(() => {
const handleFeatureFlags = (event) => {
const flags = event.detail;
setFeatureFlags(flags);
// Renderização condicional baseada em flags
if (flags.newCheckoutFlow) {
renderNewCheckout();
}
};
window.addEventListener('feature-flags:update', handleFeatureFlags);
return () => window.removeEventListener('feature-flags:update', handleFeatureFlags);
}, []);
2. Notificações de Deploy para Atualização de MFEs
// Shell - Monitoramento de deploys
const deploySource = new EventSource('/api/deployments/sse');
deploySource.onmessage = ({ data }) => {
const deployment = JSON.parse(data);
if (deployment.status === 'completed') {
// Notificar MFEs sobre nova versão disponível
window.dispatchEvent(new CustomEvent('deployment:completed', {
detail: {
mfe: deployment.mfe,
version: deployment.version,
timestamp: deployment.timestamp
}
}));
}
};
// MFE - Atualização automática
useEffect(() => {
const handleDeployment = (event) => {
const { mfe, version } = event.detail;
if (mfe === 'current-mfe') {
// Mostrar notificação de atualização
showUpdateNotification(version);
}
};
window.addEventListener('deployment:completed', handleDeployment);
return () => window.removeEventListener('deployment:completed', handleDeployment);
}, []);
3. Log de Ações em Sistemas Multitenant
// Shell - Logs de auditoria
const auditSource = new EventSource('/api/audit/sse');
auditSource.onmessage = ({ data }) => {
const auditLog = JSON.parse(data);
// Filtrar por tenant atual
if (auditLog.tenantId === getCurrentTenant()) {
window.dispatchEvent(new CustomEvent('audit:log', {
detail: auditLog
}));
}
};
// MFE - Exibir logs em tempo real
useEffect(() => {
const handleAuditLog = (event) => {
const log = event.detail;
// Adicionar ao feed de atividades
addToActivityFeed({
user: log.user,
action: log.action,
timestamp: log.timestamp,
details: log.details
});
};
window.addEventListener('audit:log', handleAuditLog);
return () => window.removeEventListener('audit:log', handleAuditLog);
}, []);
4. Monitoramento de Estados por Usuário
// Shell - Estados de sessão
const sessionSource = new EventSource('/api/session/sse');
sessionSource.onmessage = ({ data }) => {
const sessionUpdate = JSON.parse(data);
// Atualizar estado global da sessão
window.dispatchEvent(new CustomEvent('session:update', {
detail: sessionUpdate
}));
};
// MFE - Sincronização de estado
useEffect(() => {
const handleSessionUpdate = (event) => {
const session = event.detail;
// Sincronizar estado local com servidor
setUserStatus(session.status);
setLastActivity(session.lastActivity);
// Renderização condicional baseada em permissão
if (session.permissions.includes('admin')) {
showAdminPanel();
}
};
window.addEventListener('session:update', handleSessionUpdate);
return () => window.removeEventListener('session:update', handleSessionUpdate);
}, []);
📊 Comparativo Técnico (Cenário 2025)
Tecnologia | Indicado para | Considerações |
---|---|---|
SSE | Stream unidirecional leve e confiável | Sem suporte a binários |
WebSocket | Bidirecional em tempo real | Requer mais infraestrutura e estado |
WebTransport | Baixa latência sobre HTTP/3 | Suporte ainda limitado nos browsers |
Polling | Simplicidade extrema | Ineficiente e pouco reativo |
🔧 Implementação Avançada
Classe SSE Manager
class SSEManager {
constructor(baseUrl) {
this.baseUrl = baseUrl;
this.connections = new Map();
this.eventHandlers = new Map();
}
connect(endpoint, options = {}) {
const url = `${this.baseUrl}${endpoint}`;
const source = new EventSource(url);
source.onopen = () => {
console.log(`🔗 SSE conectado: ${endpoint}`);
};
source.onmessage = ({ data }) => {
try {
const event = JSON.parse(data);
this.broadcastEvent(endpoint, event);
} catch (error) {
console.error('Erro ao processar evento SSE:', error);
}
};
source.onerror = (error) => {
console.error(`❌ Erro SSE em ${endpoint}:`, error);
};
this.connections.set(endpoint, source);
return source;
}
broadcastEvent(endpoint, data) {
const eventName = `sse:${endpoint.replace('/', ':')}`;
window.dispatchEvent(new CustomEvent(eventName, { detail: data }));
}
disconnect(endpoint) {
const source = this.connections.get(endpoint);
if (source) {
source.close();
this.connections.delete(endpoint);
}
}
disconnectAll() {
this.connections.forEach((source, endpoint) => {
source.close();
});
this.connections.clear();
}
}
// Uso global
window.sseManager = new SSEManager('/api');
Hook React Personalizado
import { useEffect, useState } from 'react';
export function useSSE(endpoint, options = {}) {
const [data, setData] = useState(null);
const [isConnected, setIsConnected] = useState(false);
const [error, setError] = useState(null);
useEffect(() => {
if (!window.sseManager) {
setError('SSE Manager não inicializado');
return;
}
const eventName = `sse:${endpoint.replace('/', ':')}`;
const handleEvent = (event) => {
setData(event.detail);
setIsConnected(true);
setError(null);
};
const handleError = () => {
setIsConnected(false);
setError('Erro na conexão SSE');
};
// Conectar ao endpoint
const source = window.sseManager.connect(endpoint);
// Configurar listeners
window.addEventListener(eventName, handleEvent);
source.addEventListener('error', handleError);
return () => {
window.removeEventListener(eventName, handleEvent);
source.removeEventListener('error', handleError);
window.sseManager.disconnect(endpoint);
};
}, [endpoint]);
return { data, isConnected, error };
}
🔍 Integração com Observabilidade
Logging com Last-Event-ID
// Suporte a reconexão com Last-Event-ID
const source = new EventSource('/api/sse', {
withCredentials: true
});
let lastEventId = null;
source.onmessage = ({ data, lastEventId: eventId }) => {
lastEventId = eventId;
// Log para observabilidade
console.log('SSE Event:', {
data: JSON.parse(data),
eventId,
timestamp: new Date().toISOString()
});
};
// Reconexão com Last-Event-ID
source.addEventListener('error', () => {
setTimeout(() => {
const newSource = new EventSource(`/api/sse?lastEventId=${lastEventId}`);
// ... reconectar
}, 5000);
});
Monitoramento com Datadog/New Relic
// Métricas customizadas
function trackSSEMetrics(endpoint, eventType, latency) {
// Datadog
if (window.DD_RUM) {
window.DD_RUM.addAction('sse_event', {
endpoint,
eventType,
latency
});
}
// New Relic
if (window.newrelic) {
window.newrelic.addPageAction('sse_event', {
endpoint,
eventType,
latency
});
}
}
🚀 Benefícios em Produção
Para Microfrontends
- ✅ Comunicação desacoplada entre Shell e MFEs
- ✅ Reatividade em tempo real sem complexidade
- ✅ Isolamento de responsabilidades mantido
- ✅ Escalabilidade horizontal facilitada
Para Infraestrutura
- ✅ Baixo custo operacional comparado ao WebSocket
- ✅ Compatibilidade com CDNs e edge computing
- ✅ Suporte nativo a HTTP/2
- ✅ Facilita auditoria e rastreabilidade
Para Desenvolvedores
- ✅ Implementação simples sem dependências
- ✅ Debugging facilitado com logs nativos
- ✅ Fallback automático para reconexão
- ✅ Integração fácil com observabilidade
📚 Referências e Materiais Recomendados
- MDN Web Docs – Server-Sent Events
- WHATWG – EventSource Spec
- Cloudflare Workers – SSE Implementation
- GitHub – SSE bridge com Kafka
🎯 Conclusão
O uso de SSE em 2025 se mostra coerente com a busca por arquiteturas desacopladas, reativas e de baixo custo operacional. Quando a comunicação bidirecional não é necessária, o SSE é uma solução leve, resiliente e facilmente auditável — especialmente em ambientes com múltiplos MFEs e shell centralizado.
Quando Usar SSE:
- ✅ Notificações em tempo real
- ✅ Feature flags dinâmicas
- ✅ Logs de auditoria em tempo real
- ✅ Atualizações de estado unidirecionais
- ✅ Monitoramento de sistemas
Quando Evitar SSE:
- ❌ Comunicação bidirecional necessária
- ❌ Dados binários para transmitir
- ❌ Latência ultra-baixa crítica
- ❌ Browsers muito antigos sem suporte
Este artigo apresenta uma solução prática para reatividade em tempo real em arquiteturas de microfrontends. Para discussões técnicas, implementações ou dúvidas sobre SSE e comunicação entre MFEs, me encontre no LinkedIn ou GitHub.