---
title: "BroadcastChannel LeaderElection: Evitando Conexões WebSocket Duplicadas"
slug: broadcast-channel-leader-election
date: 2025-05-20
category: "Microfrontends"
tags: ["broadcast-channel", "leader-election", "websocket", "microfrontends", "browser-api", "javascript", "performance"]
readTime: "5 min"
excerpt: "Como usar BroadcastChannel com LeaderElection para eleger uma aba líder e evitar múltiplas conexões WebSocket, melhorando performance e UX em aplicações com microfrontends."
url: https://eliseu.dev/blog/broadcast-channel-leader-election
---

Imagine o seguinte cenário:

> **Um usuário com duas abas abertas do painel de atendimento. Ambas tentam se conectar ao WebSocket para escutar eventos em tempo real.**

## 🚨 O Problema

Quando múltiplas abas da mesma aplicação tentam se conectar simultaneamente ao WebSocket, você enfrenta:

- ❌ **Conexões duplicadas** desnecessárias
- ❌ **Custo computacional** elevado no backend
- ❌ **Tráfego de rede** excessivo
- ❌ **UX inconsistente** entre abas
- ❌ **Conflitos de estado** em tempo real

## ✅ Solução: Eleger uma Aba Líder

Usamos a lib **broadcast-channel** que implementa **LeaderElection** de forma simples, confiável e com fallback pra browsers mais antigos.

### Implementação Básica

```javascript
import { BroadcastChannel, createLeaderElection } from 'broadcast-channel';

const channel = new BroadcastChannel('ws-coordinator');
const elector = createLeaderElection(channel);

elector.awaitLeadership().then(() => {
  console.log('Aba Principal. Conectando ao WebSocket...');
  const socket = new WebSocket('wss://api.example.com/ws');
  
  socket.onmessage = (event) => {
    // Processar mensagens do WebSocket
    const data = JSON.parse(event.data);
    console.log('Dados recebidos:', data);
  };
  
  socket.onclose = () => {
    console.log('WebSocket desconectado');
  };
});
```

## 🔄 Como Funciona

### **1. Eleição de Líder**
- ✅ **Primeira aba** que executa o código se torna líder
- ✅ **Apenas uma aba** gerencia a conexão WebSocket
- ✅ **Eleição automática** quando a aba líder é fechada

### **2. Comunicação Entre Abas**
- ✅ **BroadcastChannel** permite comunicação entre abas
- ✅ **Dados compartilhados** em tempo real
- ✅ **Sincronização automática** de estado

### **3. Fallback Robusto**
- ✅ **Suporte a browsers antigos** via IndexedDB
- ✅ **Detecção automática** de aba fechada
- ✅ **Reeleição transparente** quando necessário

## 🛠️ Implementação Avançada

### **Classe WebSocketManager**

```javascript
import { BroadcastChannel, createLeaderElection } from 'broadcast-channel';

class WebSocketManager {
  constructor(url, options = {}) {
    this.url = url;
    this.options = options;
    this.socket = null;
    this.channel = new BroadcastChannel('ws-coordinator');
    this.elector = createLeaderElection(this.channel);
    this.isLeader = false;
    
    this.setupLeaderElection();
    this.setupChannelListener();
  }
  
  setupLeaderElection() {
    this.elector.awaitLeadership().then(() => {
      this.isLeader = true;
      console.log('🎯 Aba eleita como líder');
      this.connectWebSocket();
    });
  }
  
  setupChannelListener() {
    this.channel.addEventListener('message', (event) => {
      if (!this.isLeader) {
        // Processar dados recebidos da aba líder
        this.handleWebSocketData(event.data);
      }
    });
  }
  
  connectWebSocket() {
    this.socket = new WebSocket(this.url);
    
    this.socket.onopen = () => {
      console.log('🔗 WebSocket conectado (aba líder)');
    };
    
    this.socket.onmessage = (event) => {
      const data = JSON.parse(event.data);
      
      // Broadcast para outras abas
      this.channel.postMessage({
        type: 'websocket-message',
        data: data
      });
      
      // Processar localmente também
      this.handleWebSocketData(data);
    };
    
    this.socket.onclose = () => {
      console.log('🔌 WebSocket desconectado');
      this.isLeader = false;
    };
    
    this.socket.onerror = (error) => {
      console.error('❌ Erro no WebSocket:', error);
    };
  }
  
  handleWebSocketData(data) {
    // Implementar lógica específica da aplicação
    console.log('📨 Dados processados:', data);
  }
  
  sendMessage(message) {
    if (this.isLeader && this.socket?.readyState === WebSocket.OPEN) {
      this.socket.send(JSON.stringify(message));
    } else {
      // Se não for líder, enviar via channel para o líder processar
      this.channel.postMessage({
        type: 'send-message',
        data: message
      });
    }
  }
  
  disconnect() {
    if (this.socket) {
      this.socket.close();
    }
    this.channel.close();
  }
}
```

### **Uso na Aplicação**

```javascript
// Inicializar o gerenciador
const wsManager = new WebSocketManager('wss://api.example.com/ws');

// Enviar mensagem (funciona de qualquer aba)
wsManager.sendMessage({
  type: 'user-action',
  payload: { action: 'click', element: 'button' }
});

// Cleanup ao sair da página
window.addEventListener('beforeunload', () => {
  wsManager.disconnect();
});
```

## 🎯 Vantagens da Solução

### **Performance**
- ✅ **Evita conexões WebSocket duplicadas**
- ✅ **Reduz custo computacional** no backend
- ✅ **Diminui tráfego de rede** desnecessário
- ✅ **Otimiza uso de recursos** do browser

### **Experiência do Usuário**
- ✅ **UX mais previsível** e consistente
- ✅ **Sincronização automática** entre abas
- ✅ **Comportamento uniforme** independente da aba ativa
- ✅ **Transição transparente** quando aba líder é fechada

### **Arquitetura**
- ✅ **Ideal para Micro Frontends** isolados
- ✅ **Comunicação eficiente** entre componentes
- ✅ **Estado compartilhado** sem complexidade
- ✅ **Escalabilidade** para múltiplas abas

## 🔧 Casos de Uso Ideais

### **Painéis de Atendimento**
- ✅ **Chat em tempo real** sem duplicação
- ✅ **Notificações sincronizadas** entre abas
- ✅ **Status de usuário** consistente

### **Dashboards de Monitoramento**
- ✅ **Métricas em tempo real** compartilhadas
- ✅ **Alertas sincronizados** entre abas
- ✅ **Performance otimizada** do sistema

### **Aplicações Colaborativas**
- ✅ **Edição simultânea** sem conflitos
- ✅ **Presença de usuários** sincronizada
- ✅ **Comunicação eficiente** entre sessões

## 📋 Implementação com React

### **Hook Personalizado**

```javascript
import { useEffect, useRef, useState } from 'react';
import { BroadcastChannel, createLeaderElection } from 'broadcast-channel';

export function useWebSocketLeader(url) {
  const [isLeader, setIsLeader] = useState(false);
  const [data, setData] = useState(null);
  const wsManagerRef = useRef(null);
  
  useEffect(() => {
    const channel = new BroadcastChannel('ws-coordinator');
    const elector = createLeaderElection(channel);
    
    elector.awaitLeadership().then(() => {
      setIsLeader(true);
      console.log('🎯 Aba eleita como líder');
      
      const socket = new WebSocket(url);
      
      socket.onmessage = (event) => {
        const messageData = JSON.parse(event.data);
        
        // Broadcast para outras abas
        channel.postMessage({
          type: 'websocket-data',
          data: messageData
        });
        
        setData(messageData);
      };
      
      wsManagerRef.current = { socket, channel };
    });
    
    // Listener para dados de outras abas
    channel.addEventListener('message', (event) => {
      if (event.data.type === 'websocket-data') {
        setData(event.data.data);
      }
    });
    
    return () => {
      if (wsManagerRef.current) {
        wsManagerRef.current.socket.close();
        wsManagerRef.current.channel.close();
      }
    };
  }, [url]);
  
  return { isLeader, data };
}
```

### **Uso no Componente**

```javascript
import React from 'react';
import { useWebSocketLeader } from './useWebSocketLeader';

function Dashboard() {
  const { isLeader, data } = useWebSocketLeader('wss://api.example.com/ws');
  
  return (
    <div>
      <h1>Dashboard</h1>
      {isLeader && <span>🎯 Aba Líder</span>}
      {data && <div>Dados: {JSON.stringify(data)}</div>}
    </div>
  );
}
```

## 🚀 Benefícios em Produção

### **Para Desenvolvedores**
- ✅ **Código mais limpo** e organizado
- ✅ **Debugging facilitado** com logs claros
- ✅ **Manutenção simplificada** da comunicação
- ✅ **Testes mais confiáveis** e previsíveis

### **Para Usuários**
- ✅ **Performance melhorada** da aplicação
- ✅ **Experiência consistente** entre abas
- ✅ **Sincronização automática** de dados
- ✅ **Comportamento previsível** do sistema

### **Para Infraestrutura**
- ✅ **Redução de carga** no servidor WebSocket
- ✅ **Menor uso de banda** de rede
- ✅ **Escalabilidade melhorada** do sistema
- ✅ **Custos otimizados** de infraestrutura

*Este artigo apresenta uma solução prática para comunicação eficiente entre abas usando BroadcastChannel e LeaderElection. Para discussões técnicas, implementações ou dúvidas sobre WebSockets e microfrontends, me encontre no [LinkedIn](https://linkedin.com/in/eliseusantos) ou [GitHub](https://github.com/EliseuSantos).*