Skip to main content
Dietro le quinte
Dietro le quinteEngineeringDecisions

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.

Pubblicato il di AlphaCloud4 min di lettura

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