24 de Abril de 2025
Race condition na prática
Como entender bug de concorrência sem precisar começar por teoria de threads e escalonamento.
Andrews Ribeiro
Founder & Engineer
4 min Intermediario Sistemas
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:
- duas execuções mexem no mesmo estado ou no mesmo efeito colateral
- a ordem entre elas importa para o resultado correto
- 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:
- leem estoque atual
- veem valor
1 - concluem que podem vender
- 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 > 0com 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
sleepou 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
- Race condition aparece quando timing vira parte da corretude.
- O problema real costuma ser estado compartilhado sem proteção suficiente.
- Atomicidade, lock, fila e idempotencia servem a disputas diferentes.
- Nomear a invariavel do negócio melhora muito a escolha da solução.
Checklist de pratica
Use isto ao responder
- Consigo reconhecer um fluxo de read, decide, write perigoso?
- Sei explicar por que Node não elimina race condition automaticamente?
- Consigo diferenciar duplicidade de atualização concorrente?
- Sei sugerir a defesa certa para cada tipo de disputa?
Você concluiu este artigo
Próximo passo
Bugs assíncronos e race conditions Próximo passo →Compartilhar esta página
Copie o link manualmente no campo abaixo.