Long Polling vs WebSocket em Kotlin: o que escolher para tempo real
\n\nImagine: você está escrevendo um chat em Kotlin, um terminal de bolsa de valores ou um sistema de monitoramento de servidores. O cliente precisa ver as mudanças instantaneamente. A tradicional requisição HTTP "vai-e-responde" não serve aqui — os dados devem chegar sozinhos, sem "cutucadas" constantes do usuário.
\n\nNo mundo Kotlin, existem duas abordagens populares: Long Polling e WebSocket. Ambas permitem organizar a interação em tempo real, mas fazem isso de maneiras fundamentalmente diferentes. Qual escolher? Vamos descobrir com exemplos práticos, sem enrolação e aulas acadêmicas.
\n\nO que é Long Polling (e por que não morreu)
\n\nLong Polling é uma técnica onde o cliente envia uma requisição HTTP, e o servidor não responde imediatamente, mas "fica pendurado" aberto até que novos dados apareçam. Assim que os dados aparecem — o servidor envia a resposta, o cliente a processa e imediatamente abre uma nova requisição. O ciclo se repete.
\n\nParece HTTP comum, mas com um timeout longo. Nenhum protocolo adicional, nenhum handshake — tudo funciona sobre HTTP/1.1 ou HTTP/2 padrão.
\n\nExemplo de Long Polling em Kotlin (Ktor Server + OkHttp Client)
\n\nParte do servidor com Ktor (o servidor esperará até que uma mensagem apareça):
\n\nimport io.ktor.server.engine.*\nimport io.ktor.server.netty.*\nimport io.ktor.server.routing.*\nimport io.ktor.server.response.*\nimport io.ktor.http.*\nimport kotlinx.coroutines.*\n\nfun main() {\n embeddedServer(Netty, port = 8080) {\n routing {\n get("/long-poll") {\n // Simulação de espera por nova mensagem\n val message = withContext(Dispatchers.Default) {\n delay(5000) // espera 5 segundos (ou novo evento)\n "Nova mensagem: ${System.currentTimeMillis()}"\n }\n call.respondText(message, ContentType.Text.Plain)\n }\n }\n }.start(wait = true)\n}\n\n\nCliente com OkHttp:
\n\nimport okhttp3.*\n\nval client = OkHttpClient.Builder()\n .readTimeout(30, TimeUnit.SECONDS) // ponto importante!\n .build()\n\nfun startLongPolling() {\n val request = Request.Builder()\n .url("http://localhost:8080/long-poll")\n .build()\n\n client.newCall(request).enqueue(object : Callback {\n override fun onFailure(call: Call, e: IOException) {\n e.printStackTrace()\n // Obrigatoriamente reinicia o polling em caso de erro\n startLongPolling()\n }\n\n override fun onResponse(call: Call, response: Response) {\n response.use {\n if (response.isSuccessful) {\n println("Recebido: ${response.body?.string()}")\n // Imediatamente inicia a próxima requisição\n startLongPolling()\n }\n }\n }\n })\n}\n\n\nVantagens do Long Polling:
\n- \n
- Funciona em qualquer lugar, até atrás de proxies corporativos e em navegadores antigos \n
- Depuração simples — você vê requisições HTTP comuns nos logs \n
- Fácil de integrar na infraestrutura existente (balanceadores, caches, CDNs) \n
Desvantagens:
\n- \n
- Alta latência — entre o envio da requisição e o recebimento da resposta pode levar até um RTT (Round Trip Time) \n
- O servidor mantém muitas conexões abertas (cada requisição é uma thread/coroutine separada) \n
- Na reconexão, é possível perder mensagens (se não implementar idempotência) \n
WebSocket: dúplex completo
\n\nWebSocket é um protocolo separado (ws://) que estabelece uma conexão bidirecional permanente após um handshake HTTP. O servidor e o cliente podem enviar mensagens a qualquer momento, sem a sobrecarga de cabeçalhos.
\n\n