Skip to main content
Achter de schermen
Achter de schermenEngineeringDecisions

Wat een bot op meer dan 2.000 Discord servers ons heeft geleerd

Vier dingen die op grote schaal anders werken dan je aanneemt terwijl je de code schrijft.

Gepubliceerd op door AlphaCloud4 min leestijd

Een Discord bot op drie servers en dezelfde bot op meer dan tweeduizend zijn niet hetzelfde programma in een groter formaat. Een handvol aannames die in het klein volkomen onschuldig zijn, worden vanaf een bepaalde omvang precies de bugs die het moeilijkst te vinden zijn.

Hier zijn er vier die ons echte storingen hebben gekost.

1. Fouten verspreiden zich niet gelijkmatig, ze verstoppen zich

AlphaCloud draait verdeeld over meerdere processen, shards genoemd. Discord bepaalt welke server op welke shard terechtkomt, en elke shard kent alleen zijn eigen servers.

Dat levert een soort fout op die er van buitenaf uitziet als toeval: welkomstberichten werken op sommige servers en op andere niet. Geen fout in de log, geen alarm, niets. De oorzaak was één netwerkaanroep zonder timeout. Neemt de andere kant de verbinding aan en wordt hij daarna stil, dan wacht de code de rest van de levensduur van het proces. Alles daarna gebeurt nooit, en omdat er geen fout wordt gegooid, meldt niets een fout.

De les is onspectaculair en universeel: elke uitgaande aanroep heeft een bovengrens nodig. Een aanroep die eeuwig wacht, is erger dan een die mislukt, want mislukken is tenminste zichtbaar.

2. Een herstart is geen fix, het is een deadline

Zolang we de oorzaak niet kenden, hielp het betrouwbaar om de getroffen shard opnieuw te starten. Dat is precies het probleem met herstarts: ze werken, en daarmee verdwijnt de druk om de oorzaak te vinden.

We behandelen "helpt een herstart?" nu als diagnose, niet als middel. Als het helpt, leeft de kapotte toestand in het geheugen, en is er een plek in de code die hem opbouwt en nooit weer afbreekt.

Het omgekeerde geldt ook: alles wat een herstart moet overleven, hoort in de database. Loopt er een actie in meerdere stappen, bijvoorbeeld een rolwijziging over duizenden leden, en sterft het proces halverwege, dan mag die actie niet zomaar verdwijnen. Ze moet bij de volgende start worden herkend en voortgezet.

3. De limieten van Discord gelden per bot, niet per proces

Discord beperkt hoeveel verzoeken een bot per seconde mag doen. De voor de hand liggende aanname: meer processen, meer doorvoer. Fout. De limiet ligt op de bot, niet op het proces. Drie shards die elk een volledig budget hebben, komen samen op drie keer het toegestane, en Discord remt dan alle drie af.

Daarom rekent elk van onze processen uit hoeveel er in totaal zijn en neemt alleen zijn deel. Dat klinkt vanzelfsprekend, maar dat was het niet, en de bug bleef lang onzichtbaar omdat elk afzonderlijk proces zich op zichzelf keurig gedroeg.

Een verwante valkuil: terugkerende taken draaien op vaste intervallen, bijvoorbeeld elke vijf minuten. Starten alle shards tegelijk, dan vuren ze hun taken voor altijd op hetzelfde moment af. Sindsdien krijgt elk proces bij het opstarten een willekeurige verschuiving.

4. Wat mensen echt instellen, is niet wat je verwacht

Het technische deel is de ene helft. De andere: voor de meeste servers is de standaardwaarde de instelling. Een module met verkeerde standaardwaarden is op de overgrote meerderheid van de servers verkeerd ingesteld, hoe goed de instellingenpagina ook is.

Daar volgen voor ons twee dingen uit. Ten eerste kost elke standaardwaarde meer denkwerk dan de instelling zelf. Ten tweede is de betere vraag bij een nieuwe module niet "wat kun je hier instellen", maar "wat doet deze module als niemand iets instelt, en klopt dat voor een normale server".

Dat is ook de reden achter een beslissing die op het eerste gezicht als het tegendeel klinkt: sinds v1.8.0 kun je bijna elk bericht dat de bot stuurt vrij ontwerpen. Maar verplichte blokken zoals de reden in een DM over een waarschuwing of het categoriemenu in een ticketpanel kun je verplaatsen en niet verwijderen. Vrijheid in ontwerp, ja, maar niet zo ver dat een server per ongeluk iets bouwt dat eruitziet alsof het werkt en dat niet doet.

De rode draad

Drie van de vier zijn dezelfde gedachte in een ander jasje: op deze schaal is een stille fout duurder dan een luide. Een crash wordt gemeld en opgelost. Een functie die gewoon niets meer doet, kan maandenlang zo blijven, en je komt erachter via een bugmelding van iemand die de moeite nam om te schrijven.

Daarom is de vraag die we nu als eerste over nieuwe code stellen niet "werkt dit", maar "hoe ziet het eruit als het niet werkt, en zouden we het merken".

Meer artikelen