Pular para o conteudo principal

Bugs assíncronos e race conditions

Como entender falhas de timing deixando ordem, concorrência e estado compartilhado mais visíveis.

Andrews Ribeiro

Andrews Ribeiro

Founder & Engineer

O problema

Race condition assusta porque quase nunca quebra exatamente do mesmo jeito duas vezes.

Funciona local, falha em produção, some quando você coloca console.log e aparece só quando duas respostas chegam em uma ordem especifica.

Isso faz muita gente tratar bug assíncrono como azar ou magia, quando o problema real e falta de controle sobre a ordem dos eventos.

Modelo mental

Para caçar bug assíncrono, olhar só para “o que o código faz” não basta.

Você precisa olhar para:

  • a linha do tempo dos eventos
  • qual operação termina antes da outra
  • se o estado ainda era valido no momento em que a resposta chegou

Quando a investigação muda de “ler linha de código” para “desenhar a cronologia”, o bug para de parecer fantasma.

Também ajuda trocar uma frase ruim por uma melhor:

  • ruim: “o sistema ficou doido”
  • melhor: “duas operações terminaram em ordem diferente da que a UI assumia”

Quebrando o problema

Uma forma prática de capturar esse tipo de falha e esta:

  1. Liste os eventos concorrentes envolvidos.
  2. Desenhe a ordem em que eles podem terminar.
  3. Encontre o ponto em que duas operações disputam o mesmo estado.
  4. Descubra qual garantia arquitetural faltou: cancelamento, lock, id de request ou validação final.

Isso transforma bug “aleatorio” em colisao previsivel.

Essa parte importa porque concorrência não significa bagunca total. Significa que existem várias linhas do tempo validas, e o seu código precisa continuar correto em mais de uma delas.

Exemplo simples

Imagine uma busca com autocomplete:

  • o usuário digita re
  • a requisição A sai
  • ele continua e digita react
  • a requisição B sai
  • a requisição B responde rápido e mostra o resultado certo
  • a requisição A responde atrasada e sobrescreve a tela com resultado velho

O problema aqui não e o fetch.

O problema e que o frontend aceitou uma resposta velha como se ela ainda fosse a verdade atual.

As soluções maduras aqui sao claras:

  • cancelar a requisição anterior com AbortController
  • ignorar resposta com id antigo
  • atualizar a tela só se a resposta ainda corresponder ao texto atual

Nenhuma dessas soluções existe para “deixar o fetch mais rápido”. Elas existem para impedir que uma resposta antiga ganhe o direito de escrever em um estado que já mudou.

Erros comuns

  • Tentar reproduzir o bug clicando aleatoriamente sem mapear a linha do tempo.
  • Colocar setTimeout por cima do problema e torcer.
  • Assumir que assíncrono significa aleatorio e impossivel de consertar.
  • Esquecer que duas respostas validas podem destruir a UI se chegarem na ordem errada.

Como um senior pensa

Quem tem mais experiência não chama bug assíncrono de “flaky” por reflexo.

Desenha a cronologia e pergunta:

“Que sequência de eventos coloca o sistema em um estado inválido?”

Essa pergunta tira a conversa da supersticao e coloca em causalidade.

Também costuma aparecer outra pergunta boa:

“Qual garantia esta faltando para impedir que esse estado velho volte a valer?”

As vezes a resposta e cancelamento. As vezes e idempotencia. As vezes e lock. As vezes e simplesmente checar se o estado ainda continua valido antes de aplicar o resultado.

O que o entrevistador quer ver

Em entrevista de frontend ou sistemas, concorrência expõe profundidade rápido.

  • Você entender que concorrência quebra previsibilidade por natureza.
  • Você procurar ponto de colisao sobre estado mutavel compartilhado.
  • Você falar em garantias arquiteturais, não só em espalhar await.

Uma resposta forte costuma soar assim:

“Eu desenharia a linha do tempo e tentaria descobrir qual resposta ou operação chegou tarde demais e ainda assim conseguiu gravar no estado compartilhado. A partir disso, eu escolheria a garantia certa: cancelamento, lock, versão, id de request ou validação final.”

Race condition não e azar. E uma colisao que a arquitetura ainda não sabe suportar.

Resumo rápido

O que vale manter na cabeça

Checklist de pratica

Use isto ao responder

Você concluiu este artigo

Próximo artigo Rodadas de debugging Artigo anterior Consistent hashing na prática

Continue explorando

Artigos relacionados