Pegando apps que travam logo depois de publicar
No dia 25 de setembro, três publicações foram marcadas como bem-sucedidas mesmo com a API do app travando poucos segundos depois de cada inicialização. Como elas “deram certo”, nenhum rollback foi executado; uma verificação em segundo plano as reprovou alguns minutos depois, e o site inteiro passou a retornar 404. O health check contava as falhas na lista de eventos da plataforma de hospedagem, que guarda apenas os últimos cinco eventos por máquina, então um loop de travamentos mantém a lista cheia e a contagem nunca cresce. Agora ele compara o horário da falha mais recente, e uma publicação em loop de travamento falha e restaura a versão anterior.
O que uma publicação espera
Ao publicar um app com backend na Mythex, a nova versão é colocada nas máquinas da nossa plataforma de hospedagem, e um health check decide se a publicação entrou no ar ou falhou. Se falhou, um rollback recoloca a versão anterior.
O difícil é que “iniciou” não é o mesmo que “está servindo”. A plataforma informa que uma máquina iniciou assim que ela sobe. Um app que trava um segundo depois de iniciar é reiniciado imediatamente, e um instante depois aparece como iniciado de novo. Por isso o health check tinha ganhado algumas camadas ao longo do tempo:
- Olhe duas vezes. Depois que uma máquina aparece como iniciada, espere um pouco e olhe de novo. Uma falha logo na inicialização costuma reprovar essa segunda verificação.
- Fique atento a loops de travamento. Se a plataforma informar que uma máquina travou repetidamente e desistiu de reiniciá-la, reprove.
- Conte as falhas desde o início da publicação. Duas verificações de “iniciado” podem atravessar uma reinicialização. Então, se houve qualquer falha desde o início desta publicação, olhe uma terceira vez; se houver mais falhas do que na verificação anterior, o app não está se mantendo de pé.
A terceira verificação foi a que falhou aqui.
Por que a contagem ficava parada
As informações de falha vêm da lista de eventos de cada máquina: inícios, saídas, reinícios. A plataforma guarda apenas os últimos cinco eventos por máquina.
Imagine um app que trava 2,5 segundos depois de cada inicialização, como um deles fazia. Cada ciclo adiciona uma falha e um início. Depois de alguns ciclos, a lista fica cheia. Daí em diante, cada novo evento empurra um antigo para fora. A lista avança, mas sempre mantém a mesma combinação: algumas falhas, alguns inícios.
Assim, “quantas falhas desde o início da publicação” retornava o mesmo número a cada verificação. A segunda olhada via, digamos, duas falhas. A terceira também via duas — falhas diferentes, mas a mesma contagem. A verificação concluía que as falhas tinham parado, e aprovava a publicação.
Isso aconteceu três vezes em 25 de setembro, em dois apps. Em cada caso:
- a publicação foi marcada como ativa,
- nenhum rollback foi executado, porque nada tinha falhado,
- nosso reconciliador, um job em segundo plano que verifica os deploys depois do fato, reprovou a implantação alguns minutos depois,
- e o site inteiro retornou 404.
Uma publicação que falha no tempo certo é recuperável: o rollback restaura a versão anterior. Uma publicação que falha alguns minutos depois de ter sido declarada um sucesso já pulou o seu rollback.
Como encontramos
Reproduzimos localmente: pegamos uma API funcionando, deixamos ela entrar em espera e depois a republicamos com uma mudança que travava na inicialização. O health check a marcou como ativa.
Isso bateu com a produção: em cada uma das três publicações, o app morria poucos segundos depois de cada inicialização, mas a contagem de falhas que a verificação comparava nunca subia entre as verificações.
A correção: comparar a falha mais recente, não a contagem
Em vez de contar falhas, a verificação agora olha o horário da falha mais recente desde o início da publicação.
Se a segunda verificação mostrar qualquer falha desde o início da publicação, a verificação espera e olha uma terceira vez. Se a falha mais recente na terceira verificação for posterior à mais recente da segunda, a máquina travou de novo no intervalo. Ela não está se mantendo de pé, e a publicação falha com uma mensagem informando que a máquina travou repetidamente desde a publicação e continua reiniciando.
Isso funciona independentemente de quão curta é a lista de eventos. Uma janela deslizante de cinco eventos pode esconder quantas falhas houve, mas não consegue esconder que uma nova acabou de acontecer — o evento mais recente é sempre o que fica guardado.
Com essa mudança, a reprodução local se comporta corretamente: a publicação falha e a imagem anterior é restaurada. Há também um teste que simula o comportamento da plataforma — cada verificação adiciona uma falha e um início e corta a lista para cinco — e verifica que o veredito é reprovação, e não aprovação.
O que tiramos disso
- Conheça o formato dos dados que você conta. Uma contagem sobre uma lista limitada deixa de significar algo quando a lista enche. O limite não estava escondido; só não tínhamos desenhado a verificação levando-o em conta.
- Prefira “aconteceu algo novo?” a “quantas coisas aconteceram?”. O carimbo de horário mais recente sobrevive ao truncamento. Um total não.
- Uma falha tardia é pior do que uma precoce. O mesmo build quebrado é inofensivo se a publicação falha e faz rollback, e derruba um site se for declarado um sucesso antes.
- Reproduza com as condições reais. O bug exigia uma máquina que já tivesse travado o suficiente para encher a lista de eventos. Um único travamento rápido em um teste não teria revelado isso.
Essa correção acompanha outra do mesmo dia, que garantiu que o rollback recoloque a versão antiga em vez de apagá-la: uma republicação com falha nunca apaga um backend que funciona. Se o seu próprio app não publica porque trava ao iniciar, a documentação de solução de problemas de publicação e nosso guia sobre como depurar um app criado com IA são bons pontos de partida.