Skip to main content
Entre bastidores
Entre bastidoresEngineeringDecisions

Lo que nos enseñó tener un bot en más de 2000 servidores de Discord

Cuatro cosas que a gran escala funcionan distinto de lo que supones mientras escribes el código.

Publicado el por AlphaCloud4 min de lectura

Un bot de Discord en tres servidores y el mismo bot en más de dos mil no son el mismo programa a mayor tamaño. Un puñado de suposiciones completamente inofensivas a pequeña escala se convierten, a partir de cierto tamaño, justo en los bugs más difíciles de encontrar.

Aquí van cuatro que nos costaron caídas reales.

1. Los fallos no se reparten por igual, se esconden

AlphaCloud funciona repartido en varios procesos, llamados shards. Discord decide qué servidor va a qué shard, y cada shard solo conoce sus propios servidores.

Eso produce un tipo de fallo que desde fuera parece azar: los mensajes de bienvenida funcionan en unos servidores y en otros no. Ningún error en el log, ninguna alerta, nada. La causa era una sola llamada de red sin tiempo límite. Si el otro lado acepta la conexión y luego se queda callado, el código espera durante el resto de la vida del proceso. Todo lo que viene después nunca ocurre, y como no se lanza ningún error, nada informa de un error.

La lección no tiene nada de espectacular y es universal: cada llamada saliente necesita un límite superior. Una llamada que espera para siempre es peor que una que falla, porque fallar al menos se ve.

2. Un reinicio no es una solución, es un plazo

Mientras no conocíamos la causa, reiniciar el shard afectado ayudaba siempre. Ese es justo el problema de los reinicios: funcionan, y eso quita la presión de encontrar la causa.

Ahora tratamos «¿ayuda un reinicio?» como un diagnóstico, no como un remedio. Si ayuda, el estado roto vive en memoria, y hay un sitio en el código que lo construye y nunca lo desmonta.

Lo contrario también se cumple: todo lo que tiene que sobrevivir a un reinicio pertenece a la base de datos. Si hay en marcha una operación de varios pasos, por ejemplo un cambio de rol en miles de miembros, y el proceso muere a mitad, la operación no puede desaparecer sin más. Tiene que detectarse y continuarse en el siguiente arranque.

3. Los límites de Discord se aplican por bot, no por proceso

Discord limita cuántas peticiones por segundo puede hacer un bot. La suposición obvia: más procesos, más capacidad. Error. El límite está en el bot, no en el proceso. Tres shards, cada uno con el presupuesto completo, suman tres veces lo permitido, y entonces Discord frena a los tres.

Así que cada uno de nuestros procesos calcula cuántos existen en total y toma solo su parte. Suena obvio, pero no lo era, y el bug pasó mucho tiempo invisible porque cada proceso por separado parecía comportarse perfectamente.

Una trampa relacionada: las tareas recurrentes se ejecutan en intervalos fijos, por ejemplo cada cinco minutos. Si todos los shards arrancan a la vez, disparan sus tareas en el mismo instante para siempre. Desde entonces, cada proceso recibe un desfase aleatorio al arrancar.

4. Lo que la gente configura de verdad no es lo que esperas

La parte técnica es una mitad. La otra: para la mayoría de los servidores, el valor por defecto es el ajuste. Un módulo con valores por defecto equivocados está mal configurado en la inmensa mayoría de los servidores, por buena que sea la página de ajustes.

De ahí sacamos dos cosas. Primero, cada valor por defecto merece más reflexión que el ajuste en sí. Segundo, la mejor pregunta para un módulo nuevo no es «qué se puede configurar aquí», sino «qué hace este módulo cuando nadie configura nada, y es eso lo correcto para un servidor normal».

Esa es también la razón de una decisión que al principio parece lo contrario: desde la v1.8.0, casi todos los mensajes que envía el bot se pueden diseñar libremente. Pero los bloques obligatorios, como el motivo en un MD de advertencia o el menú de categorías en un panel de tickets, se pueden mover y no borrar. Libertad de diseño, sí, pero no hasta el punto de que un servidor construya sin querer algo que parece funcionar y no funciona.

El hilo común

Tres de los cuatro son la misma idea con distinto disfraz: a este tamaño, un fallo silencioso es más caro que uno ruidoso. Un crash se reporta y se arregla. Una función que simplemente deja de hacer algo puede quedarse así durante meses, y te enteras por el reporte de un bug de alguien que se tomó la molestia de escribir.

Así que la pregunta que ahora nos hacemos primero ante código nuevo no es «¿funciona esto?», sino «¿qué aspecto tiene cuando no funciona, y nos daríamos cuenta?».

Más artículos