Anatomia de um colapso mental às 2 da manhã
(zarar.dev)- Por volta das 22h, no jumpcomedy.com, todas as chamadas HTTP POST do RTK Query começaram a falhar, quebrando funcionalidades do site; como tudo funcionava normalmente no ambiente local, rastrear a causa foi difícil
- Enquanto as reclamações dos clientes se acumulavam, o operador precisou lidar sozinho com a falha, sem suporte de produção, SRE, engenheiro sênior ou gerente
- O TypeError relacionado ao
fetchno navegador não ofereceu uma pista direta, já que GET e DELETE funcionavam normalmente - Mesmo verificando Sentry, banco de dados de produção, Cloudflare, atualização do Chrome e rollback para versões antigas, nada mudava; ao inserir a api_key do PostHog, que estava vazia localmente, o problema foi reproduzido
- Depois de remover o PostHog, as funcionalidades voltaram ao normal; mais tarde, o mesmo incidente foi confirmado em issues do GitHub do PostHog e do Redux Toolkit, revelando a influência de uma ferramenta externa
A pressão criada pela falha
- A partir de cerca das 22h, no jumpcomedy.com, todas as chamadas HTTP POST baseadas em RTK Query passaram a falhar, e as principais funcionalidades deixaram de operar corretamente
- Havia mudanças implantadas recentemente, mas nada que parecesse ser a causa; como o problema não se reproduzia no ambiente local, o rastreamento ficou ainda mais difícil
- Foram pedidos ajuda nos Discords do NextJS e da Vercel, mas não houve resposta, e também não havia uma equipe de suporte de produção para assumir a resposta ao incidente
- Os e-mails de clientes continuavam se acumulando
- Perguntas dizendo que não conseguiam alterar o preço de um evento
- Perguntas dizendo que não conseguiam remover um código promocional
- Como pequenos clientes empresariais dependiam do serviço, o operador sentiu vergonha, tristeza, sensação de incompetência e síndrome do impostor
Processo de depuração e confirmação da causa
- O erro do navegador era um TypeError indicando que o
fetchtinha sido executado com um request object já usado, mas isso não apontava a causa real - Foram adicionados vários
console.log()e breakpoints para verificar headers, comprimento do token da API, ordem das chamadas etc., mas nada levou a uma causa clara - Suspeitou-se de uma atualização do Chrome, mas o problema também se reproduzia no Firefox e no Edge, então não era um problema exclusivo do navegador
- Mesmo voltando para versões antigas, a falha continuava
- Falhava também na versão de um mês antes
- Falhava também na versão de três meses antes
- Falhava também na versão de um ano antes
- Para reduzir as diferenças entre local e produção, vários candidatos foram verificados
- Remover o Sentry em produção: sem mudança
- Conectar o ambiente local ao banco de dados de produção: sem mudança
- Desativar o Cloudflare: sem mudança
- No ambiente local, para reduzir custos, a api_key do PostHog estava vazia; ao adicioná-la, o mesmo problema foi reproduzido
- No commit seguinte, ao remover o PostHog, todas as funcionalidades passaram a operar normalmente
- O mesmo problema foi confirmado depois também em issues do GitHub
1 comentários
Comentários do Hacker News
Depois de trabalhar por 1 ano como SRE em uma grande empresa global, consegui sair do modo de “pânico” de que o texto fala
Do ponto de vista do negócio, todo problema parece o fim do mundo, e é fácil entrar em pânico nessa situação, mas na prática raramente é tão ruim assim e, mesmo quando é ruim, na maioria das vezes você sobrevive sem maiores danos
Nessas situações, o ponto principal é parar por 5 a 10 minutos antes de tentar mexer em algo para corrigir e desenhar o cenário da forma mais clara possível. O medo atrapalha o julgamento racional, e sair apertando botões em pânico pode complicar ainda mais o problema. Meu truque é jogar água bem gelada no rosto e nas mãos para interromper esse circuito do medo
Depois de passar por isso algumas vezes, você ganha confiança de que não é tão terrível quanto parece e de que já lidou com situações ruins antes, então percebe que consegue aguentar mesmo sem ter alguém a quem pedir ajuda
Software comprado que não faz nada por falha de alocação de pessoal ou de configuração, funcionários perdendo milhares de horas por ano com experiência de usuário ruim e requisitos sem sentido, capacidades que não fazem função nenhuma sendo deixadas de lado, reuniões inúteis desperdiçando tempo todos os dias, funcionalidades que existem só para cumprir exigências de auditoria, executivos desperdiçando o dinheiro da empresa continuamente — esse tipo de coisa
Downtime não parece pior do que esses problemas, mas atrai muito mais atenção e pânico. Parece o contraste entre terrorismo e doença cardíaca. A empresa não se importa com o seu sono nem com a sua saúde mental e vai forçar o máximo possível. Não quer dizer que haja maldade, mas nisso ela age como um agressor: empurra mais na medida em que você recua
Um dos meus lemas de programação é “sem magia negra”. Se você não entende por que funciona, então ainda não acabou
Vejo resposta a incidentes do mesmo jeito. Se alguém não consegue explicar de forma consistente por que uma sugestão vai ter efeito, então acho que não deveria ser executada. Pode ser que um dia chegue a hora de simplesmente puxar o gatilho, mas olhando para trás, acho que nunca houve de fato um caso assim
Foi bem chocante ver executivos de alto escalão, normalmente muito calmos, começarem a jogar correções aleatórias durante um incidente
Imagine quão maior poderia ter sido o estrago se ninguém tivesse parado essa pessoa desenvolvedora solo para dizer que ela não deveria tentar popularizar
fetchÉ verdade que o medo atrapalha o julgamento racional, e eu acrescentaria que o medo também é extremamente contagioso. Quando quem está na linha de frente vê líderes, gerentes e colegas entrando em pânico, muitas vezes entra em pânico junto. Felizmente, meu VP sempre mantinha a calma e priorizava clareza acima de ação
Não sei se isso chega a ser um colapso mental, e pode até passar uma impressão errada para pessoas que realmente passam por um colapso por estresse relacionado à tecnologia
No meu caso aconteceu exatamente uma vez, e foi uma crise de ansiedade. Tive muita sorte porque minha esposa estava ao meu lado, explicou a situação e me ajudou a entender o que eu estava passando. Ela já teve várias; para mim foi a primeira e, felizmente, a última
Isso pode acontecer com qualquer pessoa, e não há nada de errado nisso por si só. É muito importante internalizar que isso não significa que você seja defeituoso ou fraco
No meu caso, o que acabou fazendo parar foi Xanax, e como eu consegui dormir, acho que vale a pena ter por perto
O que quero dizer é que pensamentos intrusivos são uma coisa, e estados realmente incontroláveis e paralisantes, como uma crise de ansiedade ou de pânico, são outra. Quando isso acontece, você não consegue trabalhar, e tudo bem
Nem todo colapso se manifesta na forma de crise de pânico ou de ansiedade. Pode se manifestar assim, mas não é a única forma. O estresse aparece de maneiras muito diferentes dependendo da pessoa e até do fator de estresse
Como não dá para saber exatamente o que aquela pessoa viveu dentro da própria cabeça, é quase impossível “diagnosticar” de fora. Mesmo que não tenha sido uma crise de pânico completa, ainda assim parece ter havido uma paralisia funcional por algumas horas
Se você pesquisar online, parece que o Xanax pode causar dependência
https://www.drugs.com/xanax.html
Não parece ser o tipo de coisa para tomar com leviandade
Há uma boa chance de vermos a grande leva de pessoas que entrou no setor de tecnologia em meados dos anos 2000 morrer de doenças relacionadas ao estresse
Como alguém que teve ansiedade severa a vida inteira, a própria ideia de uma pílula viciante que faz tudo isso desaparecer dá medo. Acho que eu acabaria dependente para sempre
O estresse dessa pessoa foi causado por uma linha de código do PostHog. O commit revertido é este: https://github.com/PostHog/posthog-js/pull/1371/commits/7598...
Dá para tirar duas lições daqui. Primeiro: se você fez deploy, então isso é seu. Portanto, quanto menos deploy você fizer, melhor, e dependências devem ser mantidas no mínimo. Segundo: coisas que não são importantes devem ficar fora do caminho crítico. O motor não pode parar porque o compressor do ar-condicionado quebrou. No navegador, isso é muito difícil de alcançar, mas ainda vale a tentativa
Pior ainda, o PostHog parece atualizar dinamicamente parte do próprio código em tempo de execução, em vez de empacotar tudo no build
A documentação menciona uma opção avançada para incluir todas as dependências no build. Entendo por que isso existe, e posso estar entendendo errado, mas, do ponto de vista do usuário, eu esperaria que o lazy loading de código em execução fosse uma opção de otimização, não o padrão. Na minha visão, isso só deveria ser usado quando um bundle completo causasse uma latência de entrega séria
O bug parece ter estado dentro de um
window.fetchmonkey-patchadohttps://github.com/PostHog/posthog-js/blob/759829c67fcb8720f...
A maior lição aqui é que, se você vai criar uma biblioteca popular e fazer monkey patch de função global, os testes precisam ser realmente muito bons
“Vamos colocar a chamada do PostHog dentro de um try/catch, por via das dúvidas” e “Por causa do PostHog, literalmente não dá para enviar requisições POST com
fetch()” são coisas completamente diferentesfetch, parece que mocking excessivo também contribuiu: https://github.com/PostHog/posthog-js/blob/main/src/_tests...As funções de fetch e XHR são totalmente mockadas para não fazer nada, então obviamente isso não detecta problemas que surgem na interação com código nativo subjacente ou com outras bibliotecas. O Cypress também está configurado, então não entendo por que tentariam mockar APIs do navegador
Se estivesse integrada de forma razoável, eu imaginaria que, no pior caso, só o processamento dos eventos de monitoramento falharia
O fato de o PostHog fazer patch de uma função global tão importante deveria ser uma funcionalidade muito bem documentada. Assim, quem usa a ferramenta saberia disso e poderia ao menos considerar essa hipótese ao depurar problemas aparentemente difíceis de explicar
Por exemplo, o Heap Analytics ainda hoje, neste mês, mexe em alguma coisa dentro do Hotwire de um jeito que quebra o Hotwire aleatoriamente e faz com que todos os cliques virem carregamentos completos de página. Na minha experiência, isso afeta entre 30% e 60% dos carregamentos. Dá para corrigir, mas eu precisei de mais de 50 horas de depuração até conseguir fazer o Heap carregar depois de todo o JavaScript do Hotwire
Como outros disseram, o bug que levou a esse estresse madrugada adentro foi uma mudança de uma linha na biblioteca PostHog[0]
Eu vejo isso como mais um lembrete da importância de dar nomes exatos às variáveis
O código
res = await originalFetch(url, init)parece inofensivo o bastante. Mas, como a declaração TypeScript mostra, o parâmetrourlnão é necessariamente uma URL:url: URL | RequestInfoQuando não é uma URL, mas um objeto RequestInfo, aí surge o problema. Isso porque um objeto Request já foi criado antes no início da implementação da função e acabou sendo “consumido”, então não pode ser usado de novo aqui
Se o parâmetro tivesse um nome mais preciso, como
urlOrRequestInfo, teria sido bem mais difícil deixar passar esse problema nessa mudançaNuma linha bem mais especulativa, como os tipos lineares vindos da lógica linear podem formalizar que um valor foi “consumido”, talvez um sistema de tipos apropriado pudesse evitar esse tipo de bug
[0] https://github.com/PostHog/posthog-js/pull/1351/commits/2497...
Basta olhar para a semântica de ownership em linguagens como Rust. Não é algo impenetrável, e especialmente com experiência fica melhor, mas ainda assim pesa bastante, a ponto de ser uma das maiores reclamações de quem está aprendendo
Foi um texto estressante, mas também engraçado. Só que a parte de se culpar me pareceu familiar demais
Eu mantenho um app iOS/macOS relativamente bem-sucedido e já empurrei um release que quebrou completamente mais de 350 mil instalações. Não foi 100% minha culpa, mas era o meu produto, então na prática não fez muita diferença
O suor frio e a vergonha naquela hora foram intensos de verdade. E, por ser App Store, a correção ainda precisava passar por revisão, o que aumentou ainda mais o tempo. Felizmente, 30 minutos depois do envio o app já entrou em revisão e foi aprovado poucos minutos depois
Conforme avancei na carreira e fui para liderança, percebi que isso foi uma experiência extremamente valiosa. Talvez eu tenha me estressado na época, mas agora essa memória já está tão distante que mal consigo alcançá-la. Hoje definitivamente não me estressa
Isso pode ser controverso, mas às vezes eu deliberadamente permito que alguém do time em início de carreira quebre a produção. Digo, quando consigo ver isso de antemão e tenho confiança de que vamos nos recuperar rápido
É senso comum dizer que é importante dar espaço para falhar, mas muitos líderes traçam a linha quando a falha afeta clientes reais. Se você não está construindo algo crítico como software para pousar aviões — o que é uma situação muito comum e afortunada — então o time precisa passar pela experiência de um incidente em produção, mesmo que isso custe a alguém em Spokane, no estado de Washington, alguns minutos sem conseguir usar o produto
Obrigado por escrever isso. Gosto especialmente de ler como as pessoas atravessam esse tipo de desafio sob pressão, geralmente virando a noite
Não só pela análise técnica pós-incidente, mas porque isso ficou melhor por também trazer a perspectiva humana que normalmente é apagada dessas histórias. Esse tipo de narrativa técnica é o tipo de coisa que só desenvolvedores independentes/solo ou fundadores conseguem compartilhar com liberdade
Só pela forma como rastreou o problema já dá para ver que ele era, antes de tudo, um programador. Foi para o próprio código e foi para os logs. Ambos são caminhos racionais e ambos podem apontar a causa, mas ele deixou passar a pista mais importante que tinha: “funcionava em localhost”
SRE, DevOps, engenheiro de plataforma, ou qualquer que seja o título do dia, eu teria focado nas diferenças entre o sistema que funcionava e o sistema que não funcionava. Teria adicionado e removido uma diferença de cada vez, ou removido e depois recolocado, até algo voltar a funcionar
Eu vejo duas coisas. 1) Existe um ambiente que funciona. 2) O ambiente que falha também funcionava antes e começou a falhar depois
Isso não quer dizer que meu método seja superior. Só quero mostrar a diferença na forma de encarar o problema. Os dois vão afunilando a busca a partir do que conhecem. Eu conheço sistemas, você conhece código
Há muito tempo, quando eu trabalhava como técnico em eletrônica, havia uma pilha de placas de processador do Perkin Elmer 7/32 retiradas de serviço. Eram placas com defeito, de várias revisões, e para cada placa só havia o esquema elétrico de uma das revisões
Eu achei que não tinha salvação, mas um técnico mais velho e mais sábio me ensinou um método
Coloque a placa boa em um extensor e rode em loop o programa de diagnóstico que falha. Observe e anote, com um osciloscópio, todos os pinos do conector. Troque pela placa defeituosa e repita
Que sinal está diferente? Siga esse sinal para trás. Se o esquema não bater, desenhe um esquema que reflita a fiação real usando um voltímetro e observação visual
Ele chamava isso de “placa boa - placa ruim”, e realmente funcionava. Não vou dizer que era eficiente em termos de custo, mas consertamos todas as placas e minha habilidade de resolver problemas em circuitos eletrônicos digitais aumentou muito
Era um tipo de trabalho de “bombeiro”. Você ficava esperando o sistema quebrar, então não importava se 2 técnicos passassem 1 semana em uma única placa de circuito
“Vamos voltar para a versão de um mês atrás. Não funciona. E a de três meses? Também não. Continua falhando. E a de um ano? Nada feito.”
Ele só reverteu o próprio código e continuou usando a atualização do PostHog que quebrou no mesmo dia? A lição que eu tiro disso é que você precisa conseguir reverter tudo, inclusive as dependências
https://github.com/PostHog/posthog/issues/24471#issuecomment...
Também existe a opção de empacotar isso diretamente
https://github.com/PostHog/posthog/issues/24471#issuecomment...
O autor original lidou bem com isso. O lado positivo desse tipo de incidente é que dele saem muitas lições valiosas
É um bom texto porque faz a gente lembrar das pessoas por trás do serviço e também mostra bem o processo de depuração
Na prática, pressão não faz ninguém depurar um problema mais rápido. Normalmente, ela atrapalha o raciocínio. É preciso ignorar o resultado o máximo possível e manter a calma
A maioria de nós já passou por algo parecido, em maior ou menor grau. Claro que o estresse de tocar a própria empresa deve ser especialmente pesado