Objetivos de aprendizaje
Después de leer este artículo podrás:
- Entender por qué el monitor tiene que estar fuera de la máquina del bot
- Configurar un heartbeat en Node.js y en Python
- Recibir alertas de caída y de recuperación en Discord y en Telegram
En esta página
Todo bot se cae alguna vez: el token se revoca, la memoria se acaba, la biblioteca lanza una excepción que nadie manejó. El problema es enterarte demasiado tarde, cuando alguien te avisa en el servidor que el bot lleva horas "offline".
Monitorear el uptime vuelve automático ese descubrimiento. La arquitectura de abajo sirve para cualquier bot sin puerto HTTP, con código en Node.js (discord.js v14) y Python (discord.py 2.x) y alertas en Discord y en Telegram. Si tu bot ya está offline ahora, mira por qué un bot de Discord se queda offline.
¿Por qué el bot no puede avisar que se cayó?#
Un proceso que murió ya no ejecuta ningún código. Eso vale para una excepción fatal, para el sistema matando el proceso por falta de memoria y para un servidor entero que se quedó sin energía o sin red. En todos esos casos, el console.log y el try/catch de tu bot no ayudan.
La regla: quien avisa de la caída tiene que estar fuera. El bot emite una señal periódica, y un monitor en otra máquina nota cuando la señal desaparece. Este patrón se llama heartbeat (o push monitor, o dead man's switch).
Hay dos tipos de verificación, y los bots casi siempre necesitan el segundo:
| Tipo | Cómo funciona | Sirve para |
|---|---|---|
| Activa (ping/HTTP) | El monitor accede a una URL o puerto de tu app | Sitios web, APIs, webhooks de Telegram |
| Heartbeat (push) | Tu app accede a una URL del monitor en cada intervalo | Bots de Gateway, workers, cron jobs |
Los bots de Discord mantienen una conexión WebSocket de salida con el Gateway y no escuchan en ningún puerto, así que no hay nada que probar desde fuera. El heartbeat lo resuelve.
¿Qué monitor externo usar?#
Cualquier servicio que ofrezca un monitor de heartbeat y notificación por webhook o Telegram sirve. Dos caminos comunes:
- Uptime Kuma: monitor de código abierto que tú mismo hospedas. Tiene un monitor de tipo Push, con URL en el formato
/api/push/<token>, y notificaciones para Discord y Telegram. La documentación del proyecto describe esa API como interna, sin garantía de estabilidad. Kuma también tiene que correr fuera de la máquina del bot; si no, se cae junto con él. - Servicio hospedado: UptimeRobot, por ejemplo, tiene un plan sin costo para proyectos personales y sin fines de lucro, con límite de monitores y de intervalo entre verificaciones. Los monitores de heartbeat y parte de las integraciones de alerta pueden estar solo en los planes de pago, así que revisa la página de precios antes de elegir.
En cualquiera de los dos, el proceso es el mismo: crear un monitor de heartbeat, copiar la URL que genera y configurar el canal de alerta.
¿Cómo enviar el heartbeat desde un bot en Node.js?#
Guarda las URLs en variables de entorno, nunca en el código. Con "type": "module" en el package.json y discord.js v14:
// monitor.js
const HEARTBEAT_URL = process.env.HEARTBEAT_URL; // URL completa del monitor
const ALERT_WEBHOOK_URL = process.env.ALERT_WEBHOOK_URL; // webhook del canal
export async function alert(text) {
try {
await fetch(ALERT_WEBHOOK_URL, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ content: text.slice(0, 2000) }),
signal: AbortSignal.timeout(10_000),
});
} catch (err) {
console.error("No se pudo enviar la alerta:", err);
}
}
export function startHeartbeat(client) {
setInterval(async () => {
if (!client.isReady()) return; // sin Gateway, sin señal
try {
await fetch(HEARTBEAT_URL, { signal: AbortSignal.timeout(10_000) });
} catch (err) {
console.error("Falló el heartbeat:", err);
}
}, 60_000);
}// index.js
import { Client, Events, GatewayIntentBits } from "discord.js";
import { alert, startHeartbeat } from "./monitor.js";
const client = new Client({ intents: [GatewayIntentBits.Guilds] });
client.once(Events.ClientReady, (c) => {
console.log(`En línea como ${c.user.tag}`);
startHeartbeat(c);
alert(`Bot iniciado: ${c.user.tag}`);
});
client.on(Events.Error, (err) => alert(`Error en el client: ${err.message}`));
client.on(Events.ShardDisconnect, (event, id) =>
alert(`Shard ${id} desconectado (código ${event.code})`),
);
process.on("unhandledRejection", (err) => alert(`Promise rechazada: ${err}`));
client.login(process.env.DISCORD_TOKEN);La clave está en client.isReady(): el heartbeat solo sale cuando el bot está de verdad conectado al Gateway. Si el proceso sigue vivo, pero el bot perdió la sesión y no se reconectó, la señal se corta y recibes la alerta. Un heartbeat que sale siempre, incluso desconectado, solo prueba que el proceso existe.
En versiones recientes de discord.js v14 el evento ready pasó a llamarse clientReady, y Events.ClientReady apunta al nombre correcto de la versión instalada. La forma antigua todavía aparece en la documentación de la v14, pero marcada como obsoleta.
¿Y en Python (discord.py 2.x)?#
import os
import aiohttp
import discord
from discord.ext import tasks
HEARTBEAT_URL = os.environ["HEARTBEAT_URL"]
class Bot(discord.Client):
async def setup_hook(self):
self.session = aiohttp.ClientSession()
self.heartbeat.start()
@tasks.loop(seconds=60)
async def heartbeat(self):
if not self.is_ready():
return
try:
timeout = aiohttp.ClientTimeout(total=10)
async with self.session.get(HEARTBEAT_URL, timeout=timeout):
pass
except Exception as err:
print("Falló el heartbeat:", err)
async def close(self):
self.heartbeat.cancel()
if getattr(self, "session", None): # puede que setup_hook no haya corrido
await self.session.close()
await super().close()
bot = Bot(intents=discord.Intents.default())
bot.run(os.environ["DISCORD_TOKEN"])La lógica es la misma: la señal solo sale si is_ready() es verdadero.
¿Cómo recibir la alerta en Discord o en Telegram?#
Hay dos tipos de alerta, y cada uno sigue un camino distinto:
- Caída detectada por el monitor (la señal se cortó): configura el canal de notificación en el propio monitor. En Discord, crea un webhook en la configuración del canal, en Integraciones, y pega la URL. En Telegram, crea un bot con BotFather, agrégalo al chat e indica el token y el
chat_id. - Eventos que el bot ve (error, desconexión de shard, reinicio): el propio código llama al webhook, como la función
alertde arriba. El webhook de Discord acepta un POST con JSON y responde204 No Contentsi todo sale bien.
Para enviar la misma alerta a Telegram directamente desde el código, la Bot API acepta JSON en sendMessage:
export async function alertTelegram(text) {
const url = `https://api.telegram.org/bot${process.env.TELEGRAM_TOKEN}/sendMessage`;
await fetch(url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ chat_id: process.env.TELEGRAM_CHAT_ID, text }),
});
}Usa un canal o chat exclusivo para alertas. Mezclarlas con la conversación normal hace que el equipo silencie el canal, y la alerta de caída pasa desapercibida.
¿Cómo comprobar que el monitoreo funciona?#
Prueba la caída antes de necesitarla:
- Inicia el bot y confirma que el monitor muestra el estado "up".
- Detén el proceso y espera el intervalo configurado más la tolerancia.
- Confirma que la alerta llegó al canal correcto. Después, vuelve a encender el bot y comprueba que llega el mensaje de "volvió".
Errores comunes:
- Monitor en la misma máquina que el bot: si esa máquina se cae, el monitor cae con ella y nadie recibe el aviso.
- Heartbeat ajeno al estado del bot: si la señal sale de un bucle que no sabe si el Gateway está conectado, sigue saliendo con el bot mudo. Ata la señal a
isReady(), como arriba. - Intervalo del monitor menor que el del bot: el monitor alerta todo el tiempo. Deja el intervalo del monitor igual o mayor que el del bot y permite al menos un fallo de tolerancia.
- Webhook expuesto: quien tenga la URL puede publicar en tu canal. Mantenla en una variable de entorno y genera otra si se filtra.
- Alerta sin contexto: incluye el nombre del bot y del shard en el mensaje, o no sabrás cuál se cayó.
Cómo hacerlo en Square Cloud#
En Square Cloud, el bot corre en un contenedor aislado y siempre encendido, con reinicio automático (activado por defecto en el deploy desde el panel) cuando el proceso termina con error. Eso reduce las caídas (mira cómo mantener un bot 24/7), pero igual necesitas saber cuándo ocurren. Un token inválido o un error de código puede dejar el bot en un ciclo de caídas, y el reinicio automático no resuelve la causa. Quedarse sin memoria detiene la aplicación hasta que le subas la RAM y la inicies de nuevo.
El aviso de caída sigue llegando desde el monitor externo con heartbeat, con el canal de alerta configurado en él. El código de este artículo funciona sin cambios: define HEARTBEAT_URL, ALERT_WEBHOOK_URL y DISCORD_TOKEN como variables de entorno de la aplicación desde el panel, la API, la CLI o la extensión de VS Code. El cambio se aplica en el siguiente reinicio.
Cuando llegue la alerta, los logs en tiempo real te ayudan a investigar: están en el panel, en la CLI, en VS Code y en la app del celular. Las métricas de CPU, RAM y red se registran cada 5 minutos y se guardan por 24 horas, así que un pico de memoria cerca de la hora de la caída aparece ahí. Para leerlos con método, mira cómo leer los logs de una aplicación.
Las bibliotecas y los recursos de cada plataforma (Discord, Telegram y WhatsApp) están en bots en Square Cloud.
Hosting de bots
Tu bot en línea 24/7, con reinicio automático
Preguntas frecuentes
¿Por qué no basta con que el bot avise cuando se cae?
Porque un bot caído no puede avisar de nada. Un proceso muerto, un servidor apagado o una red sin conexión son silenciosos. Por eso la alerta de caída tiene que venir de un monitor externo que note la falta de la señal.
¿Puedo monitorear un bot que no tiene sitio web ni puerto HTTP?
Sí. Los bots de Discord, Telegram y WhatsApp normalmente solo abren conexiones de salida, así que no hay nada que probar desde fuera. La solución es el monitor de heartbeat (o push): el bot llama a una URL del monitor a intervalos regulares.
¿Qué intervalo de heartbeat uso?
Un minuto es un buen valor por defecto. Configura el monitor para tolerar uno o dos fallos seguidos antes de alertar, así una lentitud de red aislada no genera una falsa alarma.
¿La alerta en Discord puede venir de un webhook?
Sí. Un webhook de canal acepta un POST con JSON y el campo content, de hasta 2000 caracteres. Pega la URL del webhook en la configuración de notificaciones del monitor o llámala directamente desde tu código.
Más en Bots
Ver los 33 artículos- ¿Cuánto cuesta hospedar un bot de Discord?El costo de hospedar un bot de Discord depende de la RAM, el tiempo en línea, la base de datos y los servicios externos. Aprende a estimar el tuyo.
- Correr un bot en el celular (Termux) o en tu PC vs hospedarloUn bot en tu PC o celular (Termux) se cae cuando el equipo se apaga, se suspende o pierde la red. Compara las tres opciones y cuándo sirve cada una.
- Cómo mantener tu bot de Discord en línea 24/7Para mantener un bot de Discord en línea 24/7, ejecuta el proceso en una máquina siempre encendida con reinicio automático. Compara PC, VPS con pm2 o systemd.
- Por qué tu bot de Discord se apaga o aparece offlineUn bot de Discord aparece offline cuando el proceso se cae, el token es inválido, falta una intent o se acaba la memoria. Diagnostica y corrige cada causa.