Ce que faire tourner un bot sur plus de 2 000 serveurs Discord nous a appris
Quatre choses qui fonctionnent autrement à grande échelle que ce qu'on imagine en écrivant le code.

Un bot Discord sur trois serveurs et le même bot sur plus de deux mille ne sont pas le même programme en plus grand. Une poignée d'hypothèses totalement inoffensives à petite échelle deviennent, passé une certaine taille, exactement les bugs les plus difficiles à trouver.
En voici quatre qui nous ont coûté de vraies pannes.
1. Les pannes ne se répartissent pas uniformément, elles se cachent
AlphaCloud tourne réparti sur plusieurs processus, appelés shards. Discord décide quel serveur atterrit sur quel shard, et chaque shard ne connaît que ses propres serveurs.
Cela produit une catégorie de pannes qui, vue de l'extérieur, ressemble à du hasard : les messages de bienvenue fonctionnent sur certains serveurs et pas sur d'autres. Aucune erreur dans le log, aucune alerte, rien. La cause était un seul appel réseau sans délai d'expiration. Si l'autre côté accepte la connexion puis se tait, le code attend pendant tout le reste de la vie du processus. Tout ce qui vient après n'arrive jamais, et comme aucune erreur n'est levée, rien ne signale d'erreur.
La leçon est banale et universelle : chaque appel sortant a besoin d'une limite. Un appel qui attend indéfiniment est pire qu'un appel qui échoue, parce qu'un échec est au moins visible.
2. Un redémarrage n'est pas une correction, c'est une échéance
Tant que nous ne connaissions pas la cause, redémarrer le shard concerné aidait de manière fiable. C'est précisément le problème des redémarrages : ils fonctionnent, et cela enlève la pression de trouver la cause.
Nous traitons désormais « est-ce qu'un redémarrage aide ? » comme un diagnostic, pas comme un remède. Si oui, l'état défaillant vit en mémoire, et il existe un endroit dans le code qui le construit et ne le démonte jamais.
L'inverse vaut aussi : tout ce qui doit survivre à un redémarrage a sa place dans la base de données. Si une opération en plusieurs étapes est en cours, par exemple un changement de rôle sur des milliers de membres, et que le processus meurt en plein milieu, l'opération ne doit pas simplement disparaître. Elle doit être détectée et reprise au démarrage suivant.
3. Les limites de Discord s'appliquent par bot, pas par processus
Discord limite le nombre de requêtes qu'un bot peut faire par seconde. L'hypothèse évidente : plus de processus, plus de débit. Faux. La limite porte sur le bot, pas sur le processus. Trois shards ayant chacun un budget complet font trois fois le quota autorisé, et Discord bride alors les trois.
Chacun de nos processus calcule donc combien il en existe au total et ne prend que sa part. Cela paraît évident, mais ce ne l'était pas, et le bug est resté longtemps invisible parce que chaque processus, pris isolément, semblait parfaitement se comporter.
Un piège apparenté : les tâches récurrentes tournent à intervalles fixes, disons toutes les cinq minutes. Si tous les shards démarrent en même temps, ils déclenchent leurs tâches au même instant, pour toujours. Depuis, chaque processus reçoit un décalage aléatoire au démarrage.
4. Ce que les gens configurent vraiment n'est pas ce qu'on attend
La partie technique en est une moitié. L'autre : pour la plupart des serveurs, la valeur par défaut est le réglage. Un module dont les valeurs par défaut sont mauvaises est mal configuré sur la grande majorité des serveurs, aussi bonne que soit la page de réglages.
Deux choses en découlent pour nous. D'abord, chaque valeur par défaut demande plus de réflexion que le réglage lui-même. Ensuite, la meilleure question pour un nouveau module n'est pas « que peut-on configurer ici », mais « que fait ce module quand personne ne configure rien, et est-ce juste pour un serveur normal ».
C'est aussi la raison d'une décision qui semble d'abord dire l'inverse : depuis la v1.8.0, presque chaque message que le bot envoie peut être conçu librement. Mais les blocs obligatoires, comme la raison dans un MP d'avertissement ou le menu de catégories d'un panneau de tickets, peuvent être déplacés et non supprimés. La liberté de design, oui, mais pas au point qu'un serveur construise par accident quelque chose qui a l'air de fonctionner et qui ne fonctionne pas.
Le fil conducteur
Trois des quatre sont la même idée sous des déguisements différents : à cette taille, une panne silencieuse coûte plus cher qu'une panne bruyante. Un crash est signalé et corrigé. Une fonctionnalité qui cesse simplement de faire quoi que ce soit peut rester dans cet état pendant des mois, et on l'apprend par le rapport de bug de quelqu'un qui a pris la peine d'écrire.
La question que nous posons désormais en premier sur du nouveau code n'est donc pas « est-ce que ça marche », mais « à quoi ça ressemble quand ça ne marche pas, et est-ce qu'on le remarquerait ».
Plus d'articles
Garder un œil sur 4 000 serveurs Discord : Grafana, PostHog et ce qu'ils nous ont montré
Une boucle qui causait discrètement la moitié de notre trafic, trois millions de requêtes inutiles par jour et une attaque terminée au bout d'une minute. Ce que notre monitoring voit, et ce qu'il ne voit volontairement pas.
CoulissesQuand notre fournisseur d'IA a retiré le modèle
Un changement de modèle, des réponses vides sans erreur, et une facture soudain plusieurs fois plus élevée. Ce qui a cassé, et pourquoi la cause était si difficile à voir.
CoulissesLe droit dans notre code
Un bouton de résiliation qui doit fonctionner sans connexion. Un formulaire qui ne doit jamais te refuser. Pourquoi les obligations légales sont pour nous de l'architecture, pas du texte standard.