Introdução: O Dilema do Desenvolvedor
\n\nImagine: você está escrevendo um chat, um terminal de ações ou um jogo online em Go. O cliente precisa receber atualizações instantaneamente. O bom e velho AJAX com polling periódico está descartado — muitas requisições inúteis que sobrecarregam tanto o servidor quanto a bateria do usuário. Restam dois candidatos: Long Polling (consulta longa) e WebSocket.
\n\nAmbos resolvem o problema de "tempo real", mas o fazem de maneiras fundamentalmente diferentes. Qual escolher para sua aplicação Go? Vamos entender sem rodeios, com exemplos de código reais e uma análise honesta dos prós e contras. Este artigo é seu guia no mundo das comunicações em tempo real em Go.
\n\nO que é Long Polling em Go?
\n\nLong Polling é uma evolução do polling comum. O cliente envia uma requisição HTTP ao servidor, mas o servidor não responde imediatamente se não houver dados. Ele "congela" (mantém a conexão aberta) e espera até que um novo evento ocorra. Assim que o evento acontece, o servidor envia a resposta e o cliente cria imediatamente uma nova requisição Long Polling. O ciclo se repete.
\n\nEm Go, isso é implementado de forma muito elegante graças às goroutines e canais. O servidor pode "adormecer" o manipulador da requisição até que os dados estejam disponíveis.
\n\nExemplo de servidor Long Polling em Go
\n\npackage main\n\nimport (\n "fmt"\n "net/http"\n "time"\n)\n\n// Canal para receber novas mensagens\nvar messages = make(chan string, 10)\n\nfunc longPollHandler(w http.ResponseWriter, r *http.Request) {\n select {\n case msg := <-messages:\n fmt.Fprintf(w, "Nova mensagem: %s", msg)\n case <-time.After(30 * time.Second):\n // Timeout — se nenhuma mensagem chegar em 30 segundos\n http.Error(w, "Timeout", http.StatusGatewayTimeout)\n }\n}\n\nfunc main() {\n // Goroutine simulando o surgimento de novas mensagens\n go func() {\n for {\n time.Sleep(5 * time.Second)\n messages <- fmt.Sprintf("Hora: %s", time.Now().String())\n }\n }()\n\n http.HandleFunc("/poll", longPollHandler)\n http.ListenAndServe(":8080", nil)\n}\n\n\nO cliente em JavaScript ficará assim: após receber a resposta (ou timeout), ele chama /poll novamente. Simples, confiável, funciona através de qualquer proxy e firewall.
WebSocket em Go: Dúplex Completo
\n\nWebSocket é um protocolo que, após o handshake (HTTP Upgrade), transforma a conexão em um canal bidirecional permanente. O servidor pode enviar dados ao cliente a qualquer momento, e o cliente ao servidor. Sem requisições repetidas, sem timeouts.
\n\nEm Go, a biblioteca padrão não tem suporte nativo a WebSocket, mas existe o padrão ouro — o pacote gorilla/websocket. Ele é estável, bem documentado e usado em produção por milhares de projetos.
Exemplo de servidor WebSocket em Go
\n\npackage main\n\nimport (\n "log"\n "net/http"\n "time"\n\n "github.com/gorilla/websocket"\n)\n\nvar upgrader = websocket.Upgrader{\n CheckOrigin: func(r *http.Request) bool {\n return true // Para desenvolvimento. Em produção — verificar!\n },\n}\n\nfunc wsHandler(w http.ResponseWriter, r *http.Request) {\n conn, err := upgrader.Upgrade(w, r, nil)\n if err != nil {\n log.Print("Falha no upgrade:", err)\n return\n }\n defer conn.Close()\n\n // Loop infinito de leitura e escrita\n for {\n // Lê mensagem do cliente\n _, message, err := conn.ReadMessage()\n if err != nil {\n log.Println("Erro de leitura:", err)\n break\n }\n log.Printf("Recebido: %s", message)\n\n // Envia resposta (ou notificação push)\n err = conn.WriteMessage(websocket.TextMessage, []byte("Servidor: "+time.Now().String()))\n if err != nil {\n log.Println("Erro de escrita:", err)\n break\n }\n }\n}\n\nfunc main() {\n http.HandleFunc("/ws", wsHandler)\n log.Pr