¿Por qué Telegram?

Las alertas por email se pierden entre otros mensajes. Slack es excesivo para proyectos pequeños o equipos que recién empiezan. PagerDuty tiene costos que escalan rápido. Telegram es gratuito, tiene una API de bots sólida, entrega los mensajes al instante en tu celular y configurarlo lleva menos de 15 minutos.

Este tutorial muestra cómo crear un bot de Telegram y construir una clase Ruby reutilizable para enviar notificaciones desde tus scripts y aplicaciones.


Paso 1: Crear el bot con BotFather

Abre Telegram y busca @BotFather. Inicia una conversación y ejecuta:

/newbot

BotFather te va a pedir un nombre (nombre visible) y un username (debe terminar en bot). Después de eso, te entrega un token que tiene este formato:

7412853690:AAHx3kFgPQ2vNmD8sLuYtR1WoZ4JcBqE5Vk

Guarda ese token. Lo vas a necesitar en cada llamada a la API.


Paso 2: Obtener tu Chat ID

El bot necesita saber a dónde enviar los mensajes. Cada chat (privado o grupal) tiene un ID único.

Para un chat privado:

  1. Abre una conversación con tu nuevo bot y envíale cualquier mensaje.
  2. Hace una petición HTTP al endpoint getUpdates:
curl "https://api.telegram.org/bot<TU_TOKEN>/getUpdates"

La respuesta es JSON. Busca message.chat.id:

{
  "result": [{
    "message": {
      "chat": {
        "id": 198765432,
        "type": "private"
      },
      "text": "hola"
    }
  }]
}

Ese número (198765432) es tu chat ID.

Para un chat grupal:

Agrega el bot al grupo y envía un mensaje. La respuesta de getUpdates incluirá el chat ID del grupo, que es un número negativo como -1001234567890.


Paso 3: Enviar un mensaje de prueba

Verifica que todo funciona antes de escribir Ruby:

curl -s -X POST "https://api.telegram.org/bot<TU_TOKEN>/sendMessage" \
  -d "chat_id=<TU_CHAT_ID>" \
  -d "text=Hola desde la terminal" \
  -d "parse_mode=Markdown"

Si el mensaje llega a Telegram, ya estás listo para continuar.


Paso 4: La clase TelegramNotifier en Ruby

Esta clase encapsula la API de Telegram con una interfaz limpia:

require "net/http"
require "uri"
require "json"

class TelegramNotifier
  API_URL = "https://api.telegram.org/bot%s/sendMessage"

  def initialize(token: ENV["TELEGRAM_BOT_TOKEN"], chat_id: ENV["TELEGRAM_CHAT_ID"])
    @token   = token
    @chat_id = chat_id
  end

  def notify(message, level: :info)
    prefix = {
      info:    "INFO",
      success: "SUCCESS",
      warning: "WARNING",
      error:   "ERROR"
    }[level] || "INFO"

    send_message("[#{prefix}] #{message}")
  end

  private

  def send_message(text)
    uri = URI(format(API_URL, @token))

    response = Net::HTTP.post_form(uri, {
      "chat_id"    => @chat_id,
      "text"       => text,
      "parse_mode" => "Markdown"
    })

    unless response.is_a?(Net::HTTPSuccess)
      warn "TelegramNotifier: no se pudo enviar el mensaje (#{response.code})"
    end

    response
  rescue => e
    warn "TelegramNotifier: #{e.message}"
    nil
  end
end

Define el token y el chat ID como variables de entorno:

export TELEGRAM_BOT_TOKEN="7412853690:AAHx3kFgPQ2vNmD8sLuYtR1WoZ4JcBqE5Vk"
export TELEGRAM_CHAT_ID="198765432"

Ejemplos prácticos

Notificaciones de backup

notifier = TelegramNotifier.new

begin
  # Lógica de backup
  `pg_dump miapp_produccion > /backups/db_#{Date.today}.sql`

  if $?.success?
    notifier.notify("Backup de base de datos completado: db_#{Date.today}.sql", level: :success)
  else
    notifier.notify("Falló el backup — revisar directorio /backups/", level: :error)
  end
rescue => e
  notifier.notify("El script de backup falló: #{e.message}", level: :error)
end

Notificaciones de deploy

notifier = TelegramNotifier.new

notifier.notify("Deploy iniciado — rama: #{ENV['BRANCH']} por #{ENV['USER']}", level: :info)

# ... pasos del deploy ...

notifier.notify("Deploy finalizado — #{ENV['BRANCH']} está en producción", level: :success)

Alertas de errores desde Rails

En un rescue o manejador de excepciones:

# app/lib/telegram_notifier.rb — la clase definida arriba

rescue => e
  TelegramNotifier.new.notify(
    "*Error en #{self.class}*\n`#{e.message}`",
    level: :error
  )
  raise
end

O como middleware para excepciones no manejadas:

# config/application.rb
config.exceptions_app = ->(env) do
  exception = env["action_dispatch.exception"]
  TelegramNotifier.new.notify("Excepción no manejada: #{exception.message}", level: :error)
  [500, {}, ["Internal Server Error"]]
end

Cron de monitoreo

Un script simple que verifica si un servicio responde y envía una alerta si no:

#!/usr/bin/env ruby
require_relative "telegram_notifier"
require "net/http"

SERVICIOS = {
  "API"         => "https://api.miapp.com/health",
  "Dashboard"   => "https://app.miapp.com/health"
}

notifier = TelegramNotifier.new

SERVICIOS.each do |nombre, url|
  uri = URI(url)
  response = Net::HTTP.get_response(uri)

  unless response.is_a?(Net::HTTPSuccess)
    notifier.notify("#{nombre} está CAÍDO — HTTP #{response.code}", level: :error)
  end
rescue => e
  notifier.notify("#{nombre} no responde — #{e.message}", level: :error)
end

Agregar al crontab para ejecutar cada 5 minutos:

*/5 * * * * /usr/bin/ruby /home/deploy/scripts/health_check.rb

Consideraciones de seguridad

  • Nunca escribas el token del bot directamente en el código fuente. Usa siempre variables de entorno o un gestor de secretos.
  • Si agregas el bot a un grupo, todos los miembros del grupo pueden ver los mensajes. Usa chats privados para alertas de sistema con información sensible.
  • Considera usar parse_mode=MarkdownV2 si necesitas enviar mensajes con caracteres especiales — MarkdownV2 tiene reglas de escape más estrictas pero mejor renderizado.

Resumen

PasoQué hacer
Crear botChatear con @BotFather, ejecutar /newbot
Obtener chat_idEnviar mensaje al bot, llamar a getUpdates
ProbarUsar curl para enviar un mensaje
IntegrarUsar la clase TelegramNotifier desde tus scripts

Los bots de Telegram son una de las soluciones de notificación con menor fricción disponibles. Una vez que la clase está en su lugar, agregar una notificación a cualquier script es una sola línea de código. Para proyectos personales e infraestructura propia, suele ser todo lo que necesitas.


Referencias