Pular para o conteudo principal

Race condition na prática

Como entender bug de concorrência sem precisar começar por teoria de threads e escalonamento.

Andrews Ribeiro

Andrews Ribeiro

Founder & Engineer

O problema

Tem bug que some quando você coloca log.

Tem bug que só aparece em produção.

Tem bug que acontece quando duas pessoas clicam quase ao mesmo tempo e, isoladamente, cada request parece correta.

Esse tipo de bug costuma ganhar nome assustador e explicação pior ainda. A pessoa decora “condição de corrida”, mas continua sem conseguir reconhecer o problema no código.

Modelo mental

Race condition e mais simples do que parece.

Ela acontece quando:

  1. duas execuções mexem no mesmo estado ou no mesmo efeito colateral
  2. a ordem entre elas importa para o resultado correto
  3. o sistema não protege essa disputa

Você não precisa começar falando de thread.

Pode acontecer com:

  • duas requests HTTP
  • dois workers lendo a mesma fila
  • dois cliques quase simultâneos
  • uma resposta antiga chegando depois da nova

O ponto central e este:

cada fluxo funciona sozinho, mas falha quando o tempo vira parte do problema.

Quebrando o problema

Existem alguns formatos de race condition que aparecem o tempo todo.

1. Read, modify, write

Dois fluxos leem o mesmo valor, calculam em cima dele e gravam de volta.

Se os dois leram uma versão antiga, um sobrescreve o outro.

2. Efeito colateral duplicado

O sistema processa a mesma intenção duas vezes:

  • cobra duas vezes
  • manda dois emails
  • reserva duas vezes

Aqui, timing e repetição se misturam.

3. Resultado fora de ordem

Uma busca antiga responde depois da busca nova e a tela mostra dado velho como se fosse atual.

4. Recurso escasso disputado

Duas pessoas tentam pegar a ultima vaga, o mesmo cupom ou o mesmo item de estoque.

Se não houver proteção, o sistema promete o que só existe uma vez.

Exemplo simples

Imagine estoque de um produto com valor 1.

Duas requests chegam quase juntas para comprar a ultima unidade.

As duas fazem isto:

  1. leem estoque atual
  2. veem valor 1
  3. concluem que podem vender
  4. decrementam

Se o sistema não usar operação atomica, transação ou outra proteção, você pode vender duas vezes o mesmo item.

O bug não esta em uma linha obviamente errada.

O bug esta em assumir que a leitura continua valida no momento da escrita.

Algumas formas de se proteger:

  • update atomico no banco
  • WHERE stock > 0 com verificação do número de linhas afetadas
  • lock quando o recurso e muito disputado
  • fila quando a ordem precisa ser serializada
  • idempotencia quando o risco e repetição da mesma intenção

Cada uma resolve uma familia de problema diferente.

Erros comuns

  • Achar que desabilitar botao no frontend resolve disputa real.
  • Achar que Node evita race condition só porque o JavaScript roda numa thread principal.
  • Colocar retry por cima sem tratar duplicidade.
  • Usar sleep ou timeout como se atraso fosse mecanismo de corretude.
  • Corrigir o sintoma e continuar sem proteger a regra de negócio.

Como um senior pensa

Quem já sofreu com isso em produção muda a pergunta.

Em vez de perguntar “sera que duas execuções vao bater?”, pergunta:

“Se baterem, qual verdade do negócio eu preciso continuar protegendo?”

Essa mudança e importante porque leva você para invariantes reais:

  • não vender item inexistente
  • não cobrar duas vezes
  • não sobrescrever estado novo com resposta velha

Quando a regra fica clara, a escolha da ferramenta melhora.

Se o problema e atualização concorrente, talvez operação atomica resolva. Se o problema e repetição da mesma intenção, talvez idempotencia seja a resposta. Se o problema e ordem estrita, talvez fila ou lock entrem na conversa.

O que o entrevistador quer ver

Em entrevista, o avaliador não quer um mini curso de sistemas operacionais.

Ele quer ver se você:

  • reconhece onde existe estado compartilhado
  • enxerga como a ordem muda o resultado
  • escolhe proteção coerente com o tipo de disputa
  • explica trade-off entre lock, fila, transação, operação atomica e idempotencia

Uma resposta forte costuma soar assim:

“O problema não e só concorrência. O problema e uma regra importante depender de timing sem proteção. Primeiro eu nomeio a regra que não pode quebrar. Depois escolho o mecanismo mais barato que garante isso.”

Race condition não e misterio. E regra de negócio exposta ao tempo sem defesa suficiente.

Resumo rápido

O que vale manter na cabeça

Checklist de pratica

Use isto ao responder

Você concluiu este artigo

Próximo artigo O cache não é o band-aid mágico para banco lento Artigo anterior Locks, Filas e Retries: Quando Usar Cada um

Continue explorando

Artigos relacionados