O Que Pode Dar Errado - O Que Pode Dar Errado?
O Que Pode Dar Errado?

O que dá errado em deploy de produção

Vou ser direto: a maior parte dos problemas de deploy não vem de código ruim. Vem de configuração mal entendida, dependências que mudaram sem aviso, ou simplesmente de alguém ter alterado um arquivo no servidor de produção porque achou que era "só um ajuste rápido." Eu trabalho com isso há anos e já vi servidores inteiros caírem porque uma variável de ambiente tinha um espaço em branco sobrando no final. Não é exagero. É o tipo de erro que passa despercebido até você ver o log de erro às 3 da manhã.

Por que estudar o que pode dar errado antes de ir ao ar

A palavra "o que pode dar errado" aparece em toda documentação de, mas poucas pessoas realmente fazem a lição de casa. O resultado é que você depura por três horas num problema que tinha solução em três minutos se tivesse verificado as variáveis de ambiente primeiro. Eu já perdi um sábado inteiro caçando um bug que se revelou ser um volume Docker mountado com permissões erradas. O container rodava normalmente. O serviço respondia nos primeiros endpoints. Mas quando o worker tentava escrever num arquivo no disco, recebia um erro silencioso que só aparecia nos logs do sistema operacional, não nos logs da aplicação.

A dica prática é simples: antes de qualquer deploy, rode uma checklist. Não é burocracia, é economia de tempo. Se o checklist levar 20 minutos e evitar 4 horas de debugging, o investimento vale.

Mau uso de variáveis de ambiente

Esse é o campeão absoluto. Variáveis de ambiente parecem fáceis, mas escondem armadilhas que ninguém menciona. O problema número um: valores com espaços, aspas ou caracteres especiais que não são tratados corretamente ao passar para o container ou processo filho. Se você define uma variável como DB_PASSWORD="minha senha com espaços" e depois faz echo $DB_PASSWORD sem aspas, o shell quebra a string nos espaços e sua aplicação recebe um valor incompleto.

O problema número dois: variáveis que funcionam no desenvolvimento mas não no production porque o arquivo .env não é copiado ou o sistema de orquestração sobrescreve com valores padrão. Já vi isso acontecer com tokens de API que ficavam em branco no deploy, fazendo a aplicação falhar de forma intermitente — ora funcionava, ora não, dependendo do ambiente onde o container havia sido iniciado anteriormente. Workaround prático: use um validador de ambiente antes de subir o serviço. Existem ferramentas como dotenv-safe para Node.js ou envsubst para scripts bash que verificam se todas as variáveis obrigatórias estão presentes e com formato correto. Isso custa cerca de 30 segundos para configurar e evita horas de troubleshooting.

Dependências que mudam sem aviso

Eu sempre trava o versionamento das dependências. Sem travar, você pode ganhar uma atualização automática que quebra a compatibilidade. Isso é mais comum do que parece. Uma vez, um pacote Python que eu usava para conexão com banco de dados atualizou de versão 2.1 para 2.2 e mudou o formato da string de conexão. O projeto compilava normalmente. As testes unitários passavam. Mas na prática, a aplicação não conseguia estabelecer conexão com o banco porque o parâmetro changed de host para hostname. A documentação não mencionava a mudança de forma óbvia, e o changelog estava em um repositório separado que ninguém lia.

A solução: use arquivos de lock (package-lock.json, requirements.txt gerado com pip freeze, Gemfile.lock, etc.) e configure seu pipeline para rejeitar atualizações automáticas de dependência. Períodos de atualização controlada, uma vez por mês, são suficientes. Deixe o bot do Dependabot ou Renovate criar os PRs, mas não aceite automaticamente.

Configuração de rede e DNS

Problemas de rede são os mais difíceis de diagnosticar porque parecem aleatórios. Um serviço funciona de manhã e não funciona à tarde. O DNS resolve em uma máquina e não em outra. O firewall permite conexões de entrada mas bloqueia saídas. Um caso real: eu configurei um serviço que precisava se conectar a uma API externa. Os testes locais funcionavam. O deploy em staging funcionava. Em produção, a aplicação não conseguiria acessar a API. A causa era um security group da AWS que permitia tráfego de entrada na instância mas bloqueava todo o tráfego de saída para a internet. Nenhuma mensagem de erro clara. Apenas timeout.

Checklist de rede: verifique DNS, portas de entrada e saída, certificados SSL, e restrições de firewall antes de considerar o deploy como bem-sucedido. Teste conectividade com curl ou ping dos containers/servidores para os endpoints que sua aplicação precisa alcançar.

👉 Clique no botão abaixo para saber mais sobre o assunto!

Banco de dados e migrações

Migrações de banco de dados são um dos pontos onde mais acontece coisa errada. Você executa uma migração que altera uma coluna, mas a aplicação ainda está rodando com a versão antiga que espera o schema anterior. Resultado: erro de coluna inexistente ou tipos incompatíveis. A regra de ouro: nunca faça uma migração que quebre a compatibilidade com a versão anterior da aplicação sem fazer o deploy gradativo. Se precisa renomear uma coluna, primeiro crie a nova coluna, popule com os dados, e só então remova a antiga — tudo em migrações separadas. Dessa forma, tanto a versão antiga quanto a nova da aplicação continuam funcionando durante a transição.

Também é crucial testar migrações em um ambiente que replica o volume de dados de produção. Migrações que levam segundos em staging podem levar horas ou falhar completamente em produção se houver milhões de linhas para migrar.

Recursos do servidor insuficientes

Eu já vi aplicaçõesarem porque o container foi configurado com 512MB de memória e o tráfego real exigia 1GB. O sistema operacional começa a matar processos para liberar memória. A aplicação fica instável e retorna erros aleatórios. O problema: subestimar os recursos necessários por não ter feito load testing antes do deploy. Staging com poucos usuários não reflete o comportamento em produção com tráfego real.

A solução: faça testes de carga antes de ir ao ar. Ferramentas como k6, JMeter ou even autocannon podem simular centenas ou milhares de requisições simultâneas. Meça o consumo de CPU, memória e I/O do disco. Ajuste os limites do container ou servidor com base nesses dados, não em achismos.

Logs e monitoramento ausentes

Deploy sem logging adequado é voar às cegas. Quando algo dá errado — e vai dar errado —, você precisa saber o que aconteceu. Sem logs estruturados, você passa horas coletando informações manualmente. Logging mínimo viável: pelo menos registre timestamps, nível de log, identificador da requisição (trace ID), e mensagens descritivas. Use JSON para facilitar a parseação posterior. Configure retenção de logs suficiente para investigar problemas retrospectivamente.

Alertas: configure alertas para métricas críticas como taxa de erro, latência p99, uso de memória e disponibilidade do serviço. Um alerta que chega 10 minutos depois do problema é melhor que nenhum alerta. Um alerta que chega antes do problema é ideal.

O que pode dar errado quando você pula os testes de integração

Testes unitários isolados passam. Mas quando dois serviços se comunicam na prática, algo quebra. Eu aprendi isso na marra quando meu serviço de notificação funcionava perfeitamente nos testes unitários, mas falhava em produção porque o serviço de filas de mensagem estava configurado com uma versão diferente da biblioteca de cliente. O contrato entre os serviços tinha mudado e nenhum teste de integração puxou essa informação. Testes de integração entre serviços não precisam ser perfeitos. Precisa ser pelo menos um conjunto mínimo que valide os contratos de comunicação. API contracts, formatos de mensagem, códigos de erro — tudo isso precisa ser testado contra a implementação real, não apenas contra mocks.

Rollback mal planejado

O deploy funciona. Mas uma hora depois, você descobre um bug crítico e precisa voltar. O rollback não é tão simples quanto reverter para a imagem anterior. O banco de dados já foi migrado. Os dados já foram modificados. A versão anterior da aplicação pode não ser compatível com o novo schema. Planeje o rollback antes de fazer o deploy. Documente os passos necessários. Tenha scripts de reversão de migração prontos. Teste o rollback em staging. O tempo que você gasta planejando o rollback é tempo que você economiza resolvendo uma emergência.

Erros humanos e falta de automação

Deploy manual é sinônimo de erro humano. Eu sei que às vezes você precisa fazer um hotfix rápido, mas mesmo assim, documente cada passo. O que mudou. Qual comando foi executado. Em qual servidor. Isso é importante para debug e para auditoria. A verdade: quanto mais automatizado o processo de deploy, menos coisas dão errado. CI/CD bem configurado reduz drasticamente a superfície de erro. Mas automação mal feita é pior que manual — porque você acha que está protegido e não está.

Verifique se o pipeline de CI/CD inclui: linting, testes, build, deploy em staging, testes de integração, e só então deploy em produção. Se alguma etapa falhar, o pipeline deve parar. Não deixe que um build quebrado chegue à produção por configuredomissão.