1 points par GN⁺ 2024-08-21 | 1 commentaires | Partager sur WhatsApp
  • Vers 22 h sur jumpcomedy.com, tous les appels HTTP POST de RTK Query ont commencé à échouer, cassant les fonctionnalités du site, et comme tout fonctionnait en local, il était difficile d’en identifier la cause
  • Pendant que les plaintes clients s’accumulaient, l’exploitant a dû gérer seul l’incident, sans support production, SRE, ingénieur senior ni manager
  • La TypeError liée à fetch dans le navigateur n’a pas fourni d’indice direct, d’autant que les requêtes GET et DELETE fonctionnaient normalement
  • Vérifier Sentry, la base de données de production, Cloudflare, une mise à jour de Chrome et même un rollback vers des versions antérieures n’a rien changé, mais le problème a pu être reproduit en ajoutant la clé api_key de PostHog laissée vide en local
  • Après avoir supprimé PostHog, les fonctionnalités sont revenues à la normale, et des issues GitHub côté PostHog et Redux Toolkit ont ensuite confirmé qu’il s’agissait d’un impact d’un outil externe

La pression créée par l’incident

  • À partir d’environ 22 h, sur jumpcomedy.com, tous les appels HTTP POST basés sur RTK Query se sont mis à échouer, empêchant le bon fonctionnement des principales fonctionnalités
  • Des changements avaient bien été déployés récemment, mais rien ne semblait pouvoir expliquer le problème, et comme il ne se reproduisait pas en local, l’investigation était d’autant plus difficile
  • Une demande d’aide a été envoyée sur les Discord de NextJS et Vercel, sans réponse, et il n’y avait pas non plus de structure de support production à qui passer la main
  • Les e-mails clients continuaient d’arriver
    • Demandes indiquant qu’il était impossible de modifier le prix d’un événement
    • Demandes indiquant qu’il était impossible de supprimer un code promotionnel
  • Sachant que de petites entreprises dépendaient du service, l’exploitant a ressenti de la honte, de la tristesse, un sentiment d’incompétence et le syndrome de l’imposteur

Processus de débogage et identification de la cause

  • L’erreur affichée dans le navigateur était une TypeError indiquant que fetch s’exécutait avec un request object déjà utilisé, mais elle ne révélait pas la cause réelle
  • Plusieurs console.log() et points d’arrêt ont été ajoutés pour vérifier les en-têtes, la longueur du jeton API, l’ordre des appels, etc., sans permettre d’identifier clairement la cause
  • La possibilité d’une mise à jour de Chrome a été suspectée, mais le problème se reproduisait aussi sur Firefox et Edge, ce qui excluait un problème propre à un seul navigateur
  • Les échecs continuaient même après un retour à des versions antérieures
    • Échec également sur une version d’il y a un mois
    • Échec également sur une version d’il y a trois mois
    • Échec également sur une version d’il y a un an
  • Pour réduire les différences entre l’environnement local et la production, plusieurs pistes ont été vérifiées
    • Suppression de Sentry en production : aucun changement
    • Connexion du local à la base de données de production : aucun changement
    • Désactivation de Cloudflare : aucun changement
  • En local, pour réduire les coûts, la clé api_key de PostHog était laissée vide, et le même problème a pu être reproduit dès qu’elle a été ajoutée
  • Une fois PostHog supprimé dans le commit suivant, toutes les fonctionnalités ont de nouveau marché normalement
  • Le même problème a ensuite été confirmé via des issues GitHub

1 commentaires

 
GN⁺ 2024-08-21
Avis de Hacker News
  • Après avoir travaillé pendant un an comme SRE dans une grande entreprise mondiale, j’ai réussi à sortir du mode « panique » décrit dans l’article.
    Du point de vue du business, chaque problème ressemble à une fin du monde, et il est facile de paniquer dans ce genre de situation ; mais en réalité, c’est rarement aussi grave, et même quand ça l’est, on s’en sort généralement sans dommage.
    Dans ces situations, l’essentiel est de s’arrêter 5 à 10 minutes avant de toucher quoi que ce soit pour corriger immédiatement, et d’essayer de se faire une idée aussi claire que possible de la situation. La peur empêche le jugement rationnel, et si l’on appuie sur des boutons au hasard en état de panique, on peut encore plus embrouiller le problème. Mon astuce consiste à me passer de l’eau très froide sur le visage et les mains pour couper le circuit de la peur.
    Après avoir vécu ça quelques fois, on se rend compte que ça se passe mieux qu’on ne l’imaginait, et on gagne en confiance parce qu’on a déjà géré de mauvaises situations auparavant ; on comprend qu’on peut tenir le coup même sans personne à qui demander de l’aide.

    • Quand quelque chose « casse », l’entreprise peut s’agiter dans tous les sens, mais il faut se rappeler qu’elle ne panique absolument pas face à des problèmes qui pourraient en réalité être encore plus importants.
      Par exemple, des logiciels achetés qui ne servent à rien à cause d’un échec de staffing ou de configuration, des employés qui perdent des milliers d’heures chaque année à cause d’une mauvaise expérience utilisateur et d’exigences absurdes, des capacités qui ne remplissent aucune fonction et restent en friche, des réunions inutiles qui gaspillent du temps tous les jours, des fonctionnalités qui n’existent que pour satisfaire des exigences d’audit, ou des dirigeants qui continuent de gaspiller l’argent de l’entreprise.
      Le downtime ne me paraît pas pire que ces problèmes, mais il attire beaucoup plus d’attention et de panique. Ça me fait penser au contraste entre terrorisme et maladies cardiaques. L’entreprise ne se soucie pas de votre sommeil ni de votre santé mentale, et vous poussera aussi loin que possible. Je ne dis pas que c’est malveillant, mais sur ce point, elle se comporte comme un harceleur : plus vous reculez, plus elle pousse.
    • Les pires erreurs que j’ai vues pendant de vrais incidents venaient généralement d’une surréaction.
      L’une de mes devises en programmation est : « pas de magie noire ». Si vous ne comprenez pas pourquoi ça marche, ce n’est pas terminé.
      Je vois la réponse aux incidents de la même façon. Si l’on ne peut pas expliquer de manière cohérente pourquoi la proposition de quelqu’un aurait un effet, je pense qu’il ne faut pas l’exécuter. Il arrivera peut-être un jour où il faudra simplement appuyer sur la gâchette, mais avec le recul, je crois que ce cas ne s’est finalement jamais présenté.
      C’était assez choquant de voir des cadres dirigeants, d’ordinaire très calmes, commencer à lancer au hasard des idées de correctifs pendant un incident.
    • À l’inverse, les personnes qui, sur jumpcomedy.com, devaient modifier le prix d’un événement à 2 h du matin, à ±2 fuseaux horaires près, ont dû être très déçues. Certaines d’entre elles sont peut-être même mortes.
      Imaginez à quel point les dégâts auraient été plus importants si quelqu’un avait arrêté ce développeur solo en lui disant de « ne pas essayer de populariser fetch ».
    • L’un des VP les plus admirables que je connaisse disait souvent : « Ce qui est lent est fluide, et ce qui est fluide est rapide ».
      Il est juste de dire que la peur entrave le jugement rationnel, et j’ajouterais que la peur est extrêmement contagieuse. Quand les opérationnels voient un leader, un manager ou un collègue paniquer, ils paniquent souvent à leur tour. Heureusement, mon VP restait toujours calme et privilégiait la clarté à l’action.
    • Au bout du compte, ce n’est pas vous qui prenez ce risque. Ce n’est pas votre entreprise, et elle peut vous couper à n’importe quel moment — et elle le fera effectivement. Bien sûr, exception faite si c’est votre entreprise.
  • Je ne suis pas sûr qu’il s’agisse vraiment d’un effondrement mental, et cela pourrait donner une fausse impression aux personnes qui connaissent un véritable effondrement lié au stress technique.
    Dans mon cas, ça ne m’est arrivé qu’une seule fois, et c’était une crise d’angoisse. J’ai eu énormément de chance que ma femme soit à côté de moi, m’explique la situation et m’aide à comprendre ce que je traversais. Elle en avait vécu plusieurs, mais pour moi c’était la première et, heureusement, la dernière.
    Ce genre de choses peut arriver à quelqu’un, et ce n’est pas une faute en soi. Il est vraiment important d’intérioriser que cela ne veut pas dire qu’on est défectueux ou faible.
    Dans mon cas, ce qui a fini par m’arrêter, c’était le Xanax, et comme cela m’a permis de dormir, je pense que cela vaut la peine d’en avoir à portée de main.
    Ce que je veux dire, c’est qu’il y a une différence entre des pensées intrusives et un état réellement incontrôlable et paralysant, comme une crise d’angoisse ou une crise de panique. Quand cela arrive, on devient incapable de travailler, et ce n’est pas grave.

    • https://www.webmd.com/mental-health/signs-nervous-breakdown
      Tous les effondrements ne prennent pas la forme d’une crise de panique ou d’angoisse. Ils peuvent se manifester ainsi, mais ce n’est pas la seule manière. Le stress se manifeste très différemment selon les personnes, et même selon les facteurs de stress.
      Comme on ne peut pas savoir ce que cette personne a réellement vécu dans sa tête, il est presque impossible de « diagnostiquer » de l’extérieur. Même si ce n’était pas une crise de panique complète, on dirait bien qu’elle a été fonctionnellement paralysée pendant plusieurs heures.
    • Il faut être prudent avec l’idée qu’« il est bon d’avoir du Xanax à proximité ».
      En cherchant en ligne, il semble que le Xanax puisse créer une dépendance.
      https://www.drugs.com/xanax.html
      Ça ne semble pas être le genre de chose à prendre à la légère.
    • Je ne devrais pas avoir à prendre des médicaments pour supporter des fonctionnalités toujours livrées à l’arrache, des changements poussés sans réfléchir, et les alertes PagerDuty à 3 h du matin qui en résultent.
      Il y a de fortes chances qu’on voie une grande cohorte arrivée dans la tech au milieu des années 2000 mourir de maladies liées au stress.
    • L’une des choses auxquelles je ne m’attendais pas en travaillant dans une entreprise tech enterprise, c’est le nombre de collègues qui prennent régulièrement du Xanax.
      En tant que personne ayant souffert d’une forte anxiété toute sa vie, l’idée qu’un comprimé addictif puisse faire disparaître tout ça me fait peur. J’ai l’impression que j’y resterais accroché toute ma vie.
    • En fait, j’ai été déçu parce que c’était une histoire assez ordinaire de débogage de dépendance. Comme j’ai déjà eu plusieurs fois l’impression d’être au bord de l’effondrement, j’espérais un article auquel je pourrais davantage m’identifier.
  • Le stress de cette personne venait d’une ligne de code de PostHog. Le commit annulé est ici : https://github.com/PostHog/posthog-js/pull/1371/commits/7598...
    J’y vois deux leçons. Premièrement, si vous l’avez déployé, vous en êtes propriétaire. Donc moins vous déployez, mieux c’est, et il faut minimiser les dépendances. Deuxièmement, il faut garder ce qui n’est pas important hors du chemin critique. Un moteur ne devrait pas s’arrêter parce que le compresseur de climatisation est en panne. Dans un navigateur, c’est très difficile à obtenir, mais ça vaut la peine d’essayer.

  • Pire encore, PostHog semble mettre à jour dynamiquement une partie de son propre code à l’exécution, plutôt que de l’inclure dans le build
    La documentation propose une option avancée pour inclure toutes les dépendances dans le build. Je comprends pourquoi ils font ça, et je me trompe peut-être, mais en tant qu’utilisateur, je m’attendrais à ce que le chargement différé du code exécuté ne soit pas le comportement par défaut, mais une option d’optimisation. À mon avis, il ne devrait être utilisé que lorsque le bundle complet entraîne de sérieux retards de livraison.

    • Ces leçons ont clairement de la valeur, mais ensuite quelqu’un du marketing arrive et exige qu’on ajoute PostHog ou un autre script de tracking sur le site, sans accepter un refus.
  • Le bug semble avoir été dans le window.fetch monkey-patché
    https://github.com/PostHog/posthog-js/blob/759829c67fcb8720f...
    La grande leçon ici, c’est que si l’on crée une bibliothèque populaire tout en faisant du monkey-patching de fonctions globales, les tests doivent vraiment être solides.
    « Mettons les appels à PostHog dans un try/catch au cas où » et « à cause de PostHog, on ne peut littéralement pas envoyer une requête POST avec fetch() » sont deux choses complètement différentes.

    • J’ai regardé pour comprendre pourquoi ça n’avait pas été détecté par les tests, et une simple invocation de fetch pouvait déjà provoquer une erreur. Il semble y avoir à la fois une couverture insuffisante des différentes façons d’utiliser fetch et un mocking excessif : https://github.com/PostHog/posthog-js/blob/main/src/_tests...
      Les fonctions fetch et XHR étant entièrement mockées pour ne rien faire, il est logique que les problèmes d’interaction avec les API natives sous-jacentes ou d’autres bibliothèques ne soient pas détectés. Cypress est aussi configuré, donc je ne comprends pas pourquoi ils cherchent à mocker les API du navigateur.
    • Merci d’avoir pointé ça. Je n’ai pas lu l’article en détail, mais je me demandais comment une bibliothèque de monitoring pouvait faire tomber toute l’application.
      Si elle avait été intégrée de façon raisonnable, je pensais qu’au pire le traitement des événements de monitoring échouerait.
      Le fait que PostHog patche une fonction globale aussi critique est une fonctionnalité qui devrait être très bien documentée. Ainsi, les utilisateurs le sauraient et pourraient raisonnablement y penser lorsqu’ils déboguent des problèmes difficiles à expliquer en apparence.
    • On dirait que ça a fonctionné comme prévu. Ils n’ont pas « hog » les requêtes POST ?
    • C’est courant avec ce genre de suites d’analyse. Je ne vois pas comment on peut réellement tout tester quand on touche à une API aussi centrale.
      Par exemple, Heap Analytics, encore ce mois-ci, interfère avec quelque chose dans les internals de Hotwire, casse aléatoirement Hotwire de façon complète et transforme tous les clics en chargements de page complets. D’après mon expérience, cela affecte 30 à 60 % des chargements de page. On peut corriger le problème, mais il m’a fallu plus de 50 heures de débogage pour faire en sorte que Heap se charge après tout le JavaScript de Hotwire.
  • Comme d’autres l’ont dit, le bug qui a mené à ce stress nocturne était un changement d’une ligne dans la bibliothèque PostHog[0]
    J’y vois un rappel de l’importance de donner aux variables des noms précis.
    Le code res = await originalFetch(url, init) a l’air assez inoffensif. Mais comme le montre la déclaration TypeScript, le paramètre url n’est pas nécessairement une URL : url: URL | RequestInfo
    Si ce n’est pas une URL mais un objet RequestInfo, ça pose problème. Au début de l’implémentation de la fonction, un objet Request a été créé et a déjà été « consommé » ; il ne peut donc pas être réutilisé ici.
    Si le paramètre avait eu un nom plus précis, comme urlOrRequestInfo, il aurait été plus difficile de rater ce problème lors de ce changement.
    C’est une idée beaucoup plus spéculative, mais comme les types linéaires issus de la logique linéaire permettent de formaliser le fait qu’une valeur est « consommée », un système de types approprié pourrait peut-être empêcher ce genre de bug.
    [0] https://github.com/PostHog/posthog-js/pull/1351/commits/2497...

    • Le problème des systèmes de types linéaires/affines, c’est que la barrière à l’entrée est énorme.
      Il suffit de regarder la sémantique de propriété dans un langage comme Rust. Ce n’est pas infranchissable, et ça s’améliore notamment avec l’expérience, mais c’est suffisamment lourd pour être le point dont les apprenants se plaignent le plus.
  • C’était un article stressant, mais aussi drôle. Cela dit, la partie sur l’auto-culpabilisation m’a semblé beaucoup trop familière.
    Je maintiens une application iOS/macOS assez réussie, et il m’est déjà arrivé de pousser une release qui a complètement cassé plus de 350 000 installations. Ce n’était pas entièrement ma faute, mais comme c’est mon produit, ça ne changeait pas grand-chose.
    La sueur froide et la honte à ce moment-là étaient vraiment intenses. Et comme c’était sur l’App Store, le correctif devait aussi passer par le processus de revue, ce qui rallongeait le délai. Heureusement, l’app est passée en revue 30 minutes après la soumission et a été approuvée en quelques minutes.

    • Mon premier emploi de développeur m’a « permis » de casser les choses de clients à un jeune âge, non pas parce que j’étais brillant, mais parce que j’étais incompétent.
      En avançant dans ma carrière et en passant au leadership, j’ai compris que c’était une expérience très précieuse. À l’époque, j’ai peut-être été stressé, mais aujourd’hui ce souvenir est si lointain qu’il ne m’atteint même plus. Je ne suis clairement plus stressé par ça.
      C’est peut-être controversé, mais il m’arrive de laisser des membres en début de carrière casser la production, quand je le vois venir et que je suis convaincu que nous pouvons rétablir rapidement la situation.
      Tout le monde sait qu’il est important de laisser de la place à l’échec, mais beaucoup de responsables tracent la limite dès que l’échec affecte de vrais clients. Dans le cas très courant et chanceux où l’on ne construit pas quelque chose de critique comme un logiciel qui fait atterrir des avions, il faut permettre à l’équipe de vivre une panne de production, même si cela coûte à quelqu’un à Spokane, dans l’État de Washington, quelques minutes d’indisponibilité du produit.
  • Merci d’avoir écrit ce genre de billet. J’aime lire comment les gens traversent ce type d’épreuve, surtout sous pression, généralement toute la nuit.
    C’est encore mieux parce qu’on y trouve non seulement une analyse technique post-mortem, mais aussi le point de vue humain qui disparaît habituellement de ces récits. Ce type de narration technique est probablement quelque chose que seuls de petits développeurs, des développeurs solo ou des fondateurs peuvent partager librement.

  • Rien qu’à voir la façon dont le problème a été traqué, on voit d’abord que c’est un programmeur. Il est allé vers son code, puis vers les logs. Les deux sont rationnels, et les deux pouvaient être la cause, mais il a manqué l’indice le plus important qu’il avait : « ça marchait en localhost »
    SRE, DevOps, ingénieur plateforme, peu importe le titre qu’on colle ce jour-là : je me serais concentré sur la différence entre le système qui fonctionne et celui qui ne fonctionne pas. J’aurais ajouté puis retiré les différences une par une, ou retiré puis réajouté, jusqu’à ce que quelque chose fonctionne
    Je vois deux choses. 1) Il existe un environnement qui fonctionne. 2) L’environnement qui échoue fonctionnait lui aussi à l’origine, puis a commencé à échouer
    Je ne veux pas dire que ma méthode est supérieure. Je veux seulement montrer la différence de façon d’aborder le problème. Les deux resserrent autour de ce qu’ils connaissent. Moi, je connais les systèmes ; vous, vous connaissez le code

    • Il y a longtemps, quand je travaillais comme technicien en électronique, on avait une pile de cartes processeur de Perkin Elmer 7/32 retirées du service. C’étaient des cartes en panne, avec plusieurs révisions différentes, et pour chaque carte on n’avait que le schéma d’une seule révision
      Je pensais que c’était sans espoir, mais un technicien plus âgé et plus sage m’a appris une méthode
      On branchait une bonne carte sur un extenseur, et on faisait tourner en boucle le programme de diagnostic qui échouait. Avec un oscilloscope, on observait et notait toutes les broches du connecteur. On remplaçait par une mauvaise carte et on recommençait
      Quel signal est différent ? On remonte ce signal. Si le schéma ne correspond pas, on dessine, avec un voltmètre et ses yeux, un schéma qui reflète le câblage réel
      Il appelait ça « bonne carte - mauvaise carte », et ça marchait vraiment. Je ne prétendrai pas que c’était rentable, mais on a réparé toutes les cartes, et mes compétences en dépannage de circuits électroniques numériques ont énormément progressé
      C’était une sorte de travail de « pompier ». On attendait que le système tombe en panne, donc ce n’était pas grave que deux techniciens passent une semaine sur une seule carte électronique
  • « Revenons à la version d’il y a un mois. Ça ne marche pas. Et trois mois ? Ça ne marche pas. Toujours en échec. Un an ? Pas du tout. »
    Est-ce qu’il ne revenait en arrière que sur son propre code, tout en continuant à utiliser la mise à jour de PostHog qui avait cassé le même jour ? La leçon que j’en tire, c’est qu’il faut pouvoir revenir en arrière sur tout, dépendances comprises

  • Bon article qui rappelle qu’il y a des personnes derrière les services, et qui montre aussi bien le processus de débogage
    En réalité, la pression ne vous aide pas à déboguer plus vite. En général, elle gêne la réflexion. Il faut ignorer autant que possible les conséquences et rester aussi calme que possible
    La plupart d’entre nous ont probablement vécu des situations similaires, à des degrés divers. Bien sûr, le stress lié au fait de diriger sa propre entreprise est particulièrement intense