/projects/dietbox-socket

Todos os projetos

Dietbox Socket

Atualizações ao vivo como serviço próprio, para subirem no próprio relógio.

Engenheiro de Software Sênior · 2022

NodeExpressSocket.IOApplication InsightsAzure App ServiceAzure DevOps
WebsitePrivado

Visão geral

Trinta e quatro commits em dois meses de 2022, para um serviço que sobreviveu a ambos: um servidor de tempo real que mantém cada conexão aberta, junta cada cliente a uma sala com o nome do seu id de usuário, e expõe um único endpoint para onde o resto da plataforma posta quando algo precisa ser empurrado. Ele fica fora do produto porque uma conexão de longa duração e uma requisição não são o mesmo tipo de tráfego.

O que eu fiz

Praticamente uma construção solo: trinta e três dos trinta e quatro commits, do handshake ao harness de carga que comprovou que ele aguentava.

  • O próprio servidor de tempo real: o handshake com segredo compartilhado, a atribuição de sala por id de usuário, e a desconexão imediata de um cliente que acaba sem entrar em nenhuma sala.
  • O endpoint de notificação para onde o resto da plataforma posta, e os endpoints de info e de saúde usados para observar o próprio serviço.
  • A convenção de carregamento de handlers: um handler de evento é um arquivo, carregado automaticamente a partir de um diretório.
  • O harness de teste de carga, construído para manter deliberadamente uma parte dos clientes em long-polling em vez de deixar todos fazerem upgrade.

O problema

O monolito subia uma vez por madrugada, e qualquer coisa que compartilhasse seu pipeline compartilhava seu ritmo — um canal de tempo real que só pode mudar às três da manhã é um canal de tempo real que ninguém muda. Separadamente, conexões abertas e tráfego de requisição não querem a mesma quantidade de instâncias: uma escala com quantas pessoas estão online, a outra com quantas requisições chegam.

Arquitetura

A plataforma posta uma sala, um nome de evento e um payload para o endpoint de notificação; o servidor resolve quem está naquela sala agora e empurra o evento diretamente para eles.

  1. PlatformOutro serviço da plataforma posta uma sala, um nome de evento e um payload para o endpoint de notificação.
  2. Room resolvedO servidor verifica quais conexões estão de fato naquela sala agora.
  3. Fan-outO evento é empurrado para cada cliente atualmente na sala.
  4. BrowserO cliente recebe o evento e atualiza sem um refresh.

O que faz

  • O endpoint de notificação para onde o resto da plataforma posta quando algo precisa ser empurrado.
  • Um endpoint de info que reporta a contagem de conexões ao vivo, para monitoramento.
  • Um endpoint de saúde que reporta a própria latência.
  • Um handshake com segredo compartilhado que desconecta um cliente imediatamente se ele acabar sem entrar em nenhuma sala.

Decisões de engenharia

  • Tempo real como implantação própria

    Dois motivos, ambos reais: conexões abertas e tráfego de requisição escalam em eixos diferentes, e o produto subia uma vez por madrugada — um canal que só pode mudar às três da manhã é um canal que ninguém muda. Separá-lo em um serviço próprio deixou cada eixo escalar nos seus próprios termos, e deixou este subir no próprio relógio.

  • Uma sala por id de usuário

    O endereçamento é por identidade, não por conexão, então a plataforma consegue empurrar para uma pessoa sem saber quantas abas, dispositivos ou reconexões essa pessoa tem abertos no momento.

  • Handlers carregados automaticamente de um diretório

    Adicionar um evento é adicionar um arquivo — não existe registro para lembrar de atualizar, nem handler que existe no código mas nunca foi ligado.

  • Um teste de carga que mantém clientes em long-polling

    Nem todo cliente faz upgrade para um websocket. Um teste de carga em que todos fazem mede uma população que não existe, então o harness mantém deliberadamente uma parte dos clientes em long-polling via HTTP.