L'épisode s'est déroulé un samedi. La journée avançait sans particularité lorsque l'équipe d'assistance lui a envoyé un message pour l'informer qu'un de leurs clients a un problème. Il a estimé que c'était suffisamment important pour commencer le débogage. Après 15 minutes, il a compris le problème : des commandes corrompues avaient été créées dans la base de données et il fallait les supprimer.
Cela semble trivial, n'est-ce pas ?
La base de données effacées
Il y avait quelques centaines de commandes à supprimer, Anton a donc décidé de ne pas le faire manuellement mais d'écrire une courte requête SQL (drapeau rouge 🚩 )
C'était un peu plus complexe que ça, mais pour simplifier :
Code SQL : | Sélectionner tout |
1 2 3 4 | UPDATE orders SET is_deleted = true WHERE id in (1, 2, 3) |
On mesure déjà l’ampleur du désastre…
J'ai appuyé sur CTRL+Entrée et j'ai exécuté la commande. Quand cela a pris plus d'une seconde, j'ai compris ce qui s'était passé. Le programme que j'ai utilisé (DBeaver) a vu la 3ème ligne vide et a ignoré la 4ème ligne.
Oui, j'ai supprimé toutes les commandes dans la base de données 😢
Je me sentais physiquement malade et impuissant.
J'ai appuyé sur CTRL+Entrée et j'ai exécuté la commande. Quand cela a pris plus d'une seconde, j'ai compris ce qui s'était passé. Le programme que j'ai utilisé (DBeaver) a vu la 3ème ligne vide et a ignoré la 4ème ligne.
Oui, j'ai supprimé toutes les commandes dans la base de données 😢
Je me sentais physiquement malade et impuissant.
Après une profonde inspiration, Anton savait qu'il devait agir, et vite. Il n’y avait aucune place pour faire plus d’erreurs ou perdre du temps.
La reprise s'est bien mieux faite :
* J'ai décidé de ne pas restaurer l'intégralité de la base de données, car je ne pouvais pas arrêter TOUS les systèmes, car nous en avons plusieurs indépendants. Je ne voulais pas perdre les modifications apportées lors du processus de récupération. Nous utilisons PostgreSQL géré par GCP, j'ai donc créé un nouveau clone avant la mise à jour. Ensuite, j'ai exporté uniquement les colonnes « id » et « is_deleted » du clone et j'ai importé le résultat dans la base de données de production. Ensuite, il s’agissait d’une simple requête update+select.
Donc 45 minutes d’arrêt facilement évitables…
- Arrêt des systèmes - ~5 minutes
- Création d'un clone de notre base de données avant le changement (heureusement, nous avions configuré une récupération ponctuelle) - ~ 20 minutes
- J'ai appelé mon manager pendant l'attente 😨
- J'ai mis à jour des informations de la base de données de production en fonction du clone* - ~15 minutes
- J'ai démarré nos systèmes - ~5 minutes
* J'ai décidé de ne pas restaurer l'intégralité de la base de données, car je ne pouvais pas arrêter TOUS les systèmes, car nous en avons plusieurs indépendants. Je ne voulais pas perdre les modifications apportées lors du processus de récupération. Nous utilisons PostgreSQL géré par GCP, j'ai donc créé un nouveau clone avant la mise à jour. Ensuite, j'ai exporté uniquement les colonnes « id » et « is_deleted » du clone et j'ai importé le résultat dans la base de données de production. Ensuite, il s’agissait d’une simple requête update+select.
Donc 45 minutes d’arrêt facilement évitables…
Cela peut sembler une erreur très stupide que vous ne ferez jamais (ou même que vous ne pourrez pas commettre – dans les grandes entreprises). C'est peut-être vrai. Le problème ne vient pas d'une mauvaise commande SQL. Une petite erreur humaine n’est jamais le vrai problème. Le fait que je lance cette commande n'est que la fin de toute une chaîne d'échecs.
- Travailler sur la production le week-end – pourquoi ? Dans ce cas-ci, ce n’était même pas si urgent. Personne ne m'a demandé de le réparer immédiatement. J'aurais facilement pu attendre lundi.
- Qui diable exécute quelque chose sur une base de données de production sans l'exécuter d'abord sur le contrôle qualité ?
- Pourquoi ai-je modifié manuellement la base de données et n'ai-je pas utilisé d'appel API ?
- Et s'il n'y avait pas d'API, pourquoi n'ai-je pas appelé un coéquipier et n'ai-je pas eu « 4 yeux » sur une action aussi sensible ?
- Et le pire : pourquoi n’ai-je pas utilisé les transactions ? C'est aussi simple que d'écrire « Begin », puis d'utiliser Rollback en cas d'erreur.
Les erreurs se superposent les unes aux autres. Si au moins l’une d’entre elles avait été évité, tout cela ne serait jamais arrivé. La réponse à la plupart des questions est que j’étais tout simplement trop confiant.
Au moins la reprise organisée a stoppé la chaîne. Imaginez le désastre si je ne parvenais pas à restaurer la base de données dans le bon état…
Anton Zaides
Qu’est-ce que Tchernobyl a à voir là-dedans ?
Il y a quelques mois, j’ai fini de lire « Tchernobyl : l’histoire d’une catastrophe nucléaire ». L'enchaînement d'erreurs là-bas m'a rappelé ce week-end maudit (sans sous-estimer ni comparer aux dimensions de la catastrophe de Tchernobyl).
- Il y avait un problème technologique fondamental dans le réacteur RBMK.
- Cela n’a pas été communiqué correctement. Il y a eu des incidents antérieurs impliquant ce problème, mais l’équipe de Tchernobyl ne les connaissait pas.
- L’équipe n’a pas suivi la procédure lors d’un contrôle de sécurité.
- Après l'explosion, le gouvernement soviétique a tenté de la cacher, ce qui a considérablement accru la gravité des dégâts.
Qui est responsable?
Les concepteurs du réacteur ? Les équipes des autres centrales électriques qui n’ont pas communiqué sur les problèmes qu’elles rencontraient ? L'équipe de Tchernobyl ? Le gouvernement soviétique ?
Tous. Les catastrophes ne sont jamais causées par une seule erreur, mais par une chaîne d’erreurs. Notre travail consiste à faire de notre mieux pour couper la chaîne le plus tôt possible.
Les conséquences
Je ne savais pas à quoi m’attendre de la discussion avec mon manager lundi.
Il m’a surpris : « Assurez-vous que cela ne se reproduise plus. Mais je préfère que ce soit ainsi : vous avez commis une erreur parce que vous êtes dévoué et que vous aimez aller vite. Les gens qui ont un penchant pour l’action cassent les choses ».
C'est exactement ce que j'avais besoin d'entendre. Une approche trop « câline » disant « Ce n’est pas grave, ne vous inquiétez pas, merci d’avoir réparé ! » aurait semblé fausse. D'un autre côté, je me sentais déjà comme une merde, donc inutile de m'humilier davantage.
Depuis lors:
- Nous nous efforçons de supprimer le besoin d'accès à la base de données, en créant les appels API pertinents
- J'exécute toujours des requêtes sur le contrôle qualité en premier (je sais... évident, n'est-ce pas ? Rien ne fait plus tenir une leçon qu'un désastre)
- Je consulte le Premier ministre pour comprendre ce qui est vraiment urgent et ce qui peut attendre.
- Toute requête de mise à jour/insertion/suppression en production est effectuée par 2 personnes. Celui-ci a en fait évité d’autres erreurs !
- J'ai commencé à utiliser les transactions 🤦 ♂️
Appliquer les leçons dans votre équipe
Après l'incident, j'ai partagé une explication détaillée avec mon équipe. Je ne cache rien et ne minimise pas ma faute.
Il y a un équilibre fragile entre faire honte aux gens et ne pas leur demander de rendre des comptes. Lorsque VOUS faites des erreurs, c’est une excellente occasion d’envoyer le bon message.
Si vous vous excusez 1000 fois, ils penseront que vous attendez la même chose d’eux.
Si vous vous moquez de l’incident, en ignorant les implications, ils penseront que ce n’est pas grave.
Si vous êtes responsable, apprenez et améliorez-vous, ils se comporteront de la même manière.
Pour résumer, voici ce qu'il propose:
- Encouragez les gens à agir, à se soucier du client et à résoudre les problèmes. C’est ainsi que les startups réussissent.
- Lorsque des erreurs sont commises, tenez la personne responsable. Ensemble, comprenez comment cela aurait pu être évité.
- Pas besoin de faire en sorte que les gens se sentent plus mal qu’ils ne le font déjà. Certaines personnes ont besoin de plus de responsabilités, d’autres de plus d’encouragements. Je préfère toujours pécher par excès d’encouragement.
D'autres conseils
Certains professionnels du secteur ont rajouté quelques éléments qui sont susceptibles d'aider des collègues dans la situation. Par exemple :
Vous avez manqué certains points clés par la suite.
- Apprenez les transactions de base de données et comment effectuer une restauration. N'exécutez rien d'autre que select to prod sans transaction.
- N'utilisez pas de client de base de données pour vous connecter à votre base de données de production, sauf si vous disposez d'un compte en lecture seule. Utilisez uniquement le propre client de la base de données lorsque vous effectuez des changements d'état en production.
- J'espère que vous utilisez un VPN lors de la connexion à votre base de données.
En fait, je blâme l'entreprise. Permettre aux développeurs de faire en production tout ce qui ne peut pas être facilement annulé est un défaut de gestion.
Il y a 100 % de chances que quelqu'un finisse par faire quelque chose de stupide et de terrible et qu'un rétablissement rapide soit nécessaire.
S'ils ne peuvent pas faire ça, allez trouver le responsable le plus proche et blâmez-le.
Il y a 100 % de chances que quelqu'un finisse par faire quelque chose de stupide et de terrible et qu'un rétablissement rapide soit nécessaire.
S'ils ne peuvent pas faire ça, allez trouver le responsable le plus proche et blâmez-le.
L'erreur n'était pas la requête mais le fait de ne pas avoir effectué de sauvegarde avant d'exécuter la requête
Je fais systématiquement des sauvegardes avant d'exécuter la suppression, la mise à jour, l'insertion d'une requête, etc. Si quelque chose ne va pas, je peux réimporter la base de données/la table en quelques secondes - viva adminer
Je fais systématiquement des sauvegardes avant d'exécuter la suppression, la mise à jour, l'insertion d'une requête, etc. Si quelque chose ne va pas, je peux réimporter la base de données/la table en quelques secondes - viva adminer
Les transactions sont vos amies, quelle que soit la simplicité du changement
Et vous ?
Quelle lecture faites-vous de cette situation ? De l'erreur du développeur à sa réaction ?
Que pensez-vous des leçons qu'il propose d'en tirer ? Laquelle/Lesquelles vous semble(nt) la/les plus pertinente(s) ?
Avez-vous déjà utilisé DBeaver ? Qu'en pensez-vous ?
Avez-vous des anecdotes à raconter sur une situation similaire ?