Cosa ci ha insegnato gestire un bot su oltre 2.000 server Discord
Quattro cose che su larga scala funzionano diversamente da come pensi mentre scrivi il codice.

Un bot Discord su tre server e lo stesso bot su oltre duemila non sono lo stesso programma in formato più grande. Una manciata di ipotesi del tutto innocue in piccolo diventano, oltre una certa dimensione, proprio i bug più difficili da trovare.
Eccone quattro che ci sono costate interruzioni reali.
1. I guasti non si distribuiscono in modo uniforme, si nascondono
AlphaCloud gira suddiviso su più processi, chiamati shard. È Discord a decidere quale server finisce su quale shard, e ogni shard conosce solo i propri server.
Ne nasce una classe di guasti che da fuori sembra casuale: i messaggi di benvenuto funzionano su alcuni server e su altri no. Nessun errore nel log, nessun allarme, niente. La causa era una singola chiamata di rete senza timeout. Se l'altra parte accetta la connessione e poi tace, il codice aspetta per tutto il resto della vita del processo. Tutto ciò che viene dopo non succede mai, e siccome non viene lanciato nessun errore, nessuno segnala un errore.
La lezione è poco spettacolare e universale: ogni chiamata in uscita ha bisogno di un limite massimo. Una chiamata che aspetta per sempre è peggio di una che fallisce, perché fallire almeno si vede.
2. Un riavvio non è una correzione, è una scadenza
Finché non conoscevamo la causa, riavviare lo shard interessato aiutava in modo affidabile. È proprio questo il problema dei riavvii: funzionano, e questo toglie la pressione di trovare la causa.
Ora trattiamo "un riavvio aiuta?" come una diagnosi, non come un rimedio. Se aiuta, lo stato rotto vive in memoria, e c'è un punto nel codice che lo costruisce e non lo smonta mai.
Vale anche il contrario: tutto ciò che deve sopravvivere a un riavvio va nel database. Se è in corso un'operazione in più passaggi, per esempio un cambio di ruolo su migliaia di membri, e il processo muore a metà, l'operazione non deve semplicemente svanire. Deve essere rilevata e proseguita all'avvio successivo.
3. I limiti di Discord valgono per bot, non per processo
Discord limita quante richieste al secondo può fare un bot. L'ipotesi ovvia: più processi, più capacità. Sbagliato. Il limite è sul bot, non sul processo. Tre shard ciascuno con il budget pieno fanno tre volte la quota consentita, e Discord a quel punto rallenta tutti e tre.
Per questo ognuno dei nostri processi calcola quanti ne esistono in totale e prende solo la propria parte. Sembra ovvio, ma non lo era, e il bug è rimasto invisibile a lungo perché ogni singolo processo, preso da solo, sembrava comportarsi in modo impeccabile.
Una trappola collegata: i lavori ricorrenti girano a intervalli fissi, per esempio ogni cinque minuti. Se tutti gli shard partono nello stesso momento, eseguono i loro lavori nello stesso istante per sempre. Da allora ogni processo riceve uno scostamento casuale all'avvio.
4. Ciò che le persone configurano davvero non è ciò che ti aspetti
La parte tecnica è una metà. L'altra: per la maggior parte dei server, l'impostazione predefinita è l'impostazione. Un modulo con valori predefiniti sbagliati è configurato male sulla stragrande maggioranza dei server, per quanto buona sia la pagina delle impostazioni.
Per noi ne derivano due cose. Primo, ogni valore predefinito richiede più riflessione dell'impostazione stessa. Secondo, per un nuovo modulo la domanda migliore non è "cosa si può configurare qui" ma "cosa fa questo modulo quando nessuno configura niente, ed è giusto per un server normale".
È anche il motivo dietro una decisione che a prima vista sembra l'opposto: dalla v1.8.0 quasi ogni messaggio che il bot invia può essere progettato liberamente. Ma i blocchi obbligatori, come il motivo in un DM di avvertimento o il menu delle categorie in un pannello ticket, si possono spostare e non eliminare. Libertà di design sì, ma non fino al punto in cui un server costruisce per sbaglio qualcosa che sembra funzionare e non funziona.
Il filo comune
Tre delle quattro sono lo stesso pensiero in costumi diversi: a queste dimensioni, un guasto silenzioso costa più di uno rumoroso. Un crash viene segnalato e corretto. Una funzionalità che semplicemente smette di fare qualcosa può restare così per mesi, e lo scopri da una segnalazione di bug di qualcuno che si è preso la briga di scrivere.
Per questo la domanda che ora poniamo per prima su codice nuovo non è "funziona?", ma "che aspetto ha quando non funziona, e ce ne accorgeremmo?".
Altri articoli
Tenere d'occhio 4.000 server Discord: Grafana, PostHog e cosa ci hanno mostrato
Un loop che causava in silenzio metà del nostro traffico, tre milioni di richieste inutili al giorno e un attacco finito dopo un minuto. Cosa vede il nostro monitoraggio, e cosa volutamente non vede.
Dietro le quinteQuando il nostro fornitore di IA ha ritirato il modello
Un cambio di modello, risposte vuote senza alcun errore e una bolletta improvvisamente molte volte più alta. Cosa si è rotto, e perché la causa era così difficile da vedere.
Dietro le quinteLa legge dentro il nostro codice
Un pulsante di disdetta che deve funzionare senza login. Un modulo che non deve mai respingerti. Perché per noi gli obblighi legali sono architettura, non testo di contorno.