stamatios
← Voltar ao feed
Esteiras se unem com braço robótico reordenando caixas numeradas, metáfora de ordenação em WebSockets e SSE
Dev & Engenharia

WebSockets vs SSE: a questão certa é ordem e correção, não latência

resumo de ~3 min

A questão central: ordem dos eventos

A comparação entre WebSockets e Server-Sent Events (SSE) não deveria se concentrar principalmente na latência, mas em como garantir a ordem e a correção dos eventos exibidos ao usuário. Embora o uso de WebSockets possa reduzir trabalho de autenticação e o tamanho das mensagens - especialmente no Phoenix LiveView, que envia diferenças da interface em vez de HTML completo - esses benefícios são considerados secundários diante do risco de inconsistência causado por fluxos de dados concorrentes.

Quando operações relacionadas à mesma interface são entregues por canais diferentes, eventos podem chegar em uma ordem distinta daquela em que foram processados. O exemplo apresentado envolve uma lista de tags: enquanto uma operação adiciona “elixir”, outra remove “javascript”. Se a atualização resultante da remoção chegar depois da atualização da adição, a interface pode terminar mostrando apenas “erlang” e “clojure”, como se “elixir” nunca tivesse sido incluída. O estado visual pode permanecer incorreto indefinidamente, até que a página seja atualizada ou outro evento provoque uma nova sincronização.

O texto ressalta que esse comportamento não é um problema intrínseco ao SSE. A mesma disputa pode ocorrer em uma aplicação que use WebSockets para algumas operações e Fetch para outras, caso diferentes fluxos atualizem os mesmos componentes. A causa é a ausência de uma ordem causal compartilhada entre as requisições, e não o protocolo isoladamente. Além disso, chamar o problema de “consistência eventual” seria incorreto: nesse conceito, as cópias dos dados devem convergir quando não houver novas atualizações, o que não acontece se a interface puder permanecer obsoleta sem novos eventos.

Alternativas e custos

Uma forma de usar SSE com Fetch seria permitir que apenas um fluxo entregue atualizações. O Fetch faria a alteração, mas não renderizaria a lista; o cliente aguardaria a atualização pelo SSE. Essa solução pode aumentar a latência, pois as atualizações precisariam passar por um sistema de filas para circular entre servidores. O transporte de long polling do Phoenix segue lógica semelhante, embora o Phoenix possa eliminar uma etapa ao permitir comunicação direta entre nós por meio do Distributed Erlang.

Outra possibilidade é o SSE apenas avisar que há dados novos e instruir o cliente a recarregar o estado. Isso evita algumas etapas internas no servidor, mas tende a aumentar a carga, porque exige novas requisições para buscar os dados. Também seria necessário impedir vários Fetch simultâneos, enfileirando as operações no cliente e priorizando as interações do usuário.

Ordenar os eventos no próprio cliente também pode funcionar, mas é mais complexo do que parece. Não há necessariamente garantia de que um evento de criação chegará antes do de exclusão, nem de que a ordem das atualizações corresponderá às operações no banco de dados. Plataformas como Electric existem para lidar com esse tipo de problema.

Conclusão

A recomendação é avaliar, em qualquer escolha entre WebSockets e SSE, como os eventos preservarão a ordem correta e evitarão dados obsoletos ou incorretos. WebSockets oferecem um canal bidirecional que pode simplificar a preservação da causalidade entre ações do usuário e atualizações do servidor. SSE com Fetch pode ser utilizado, mas frequentemente envolve maior latência e complexidade interna. O texto conclui ainda que o Phoenix, com Elixir e Distributed Erlang, pode simplificar a operação e reduzir a latência.