Ir al contenido

Runbooks

El motor detecta y reporta; no se repara solo en bucle. Una instancia caída o trabada abre una alerta, sube una métrica y queda en el log, y un operador decide qué hacer. Esta página dice dónde mirar y resume los procedimientos (los runbooks) que viven en docs/runbooks/ del repositorio.

  • Sin datos personales. Ningún paso pide ni copia teléfonos, JID, nombres de contactos, textos de mensajes, QR, tokens ni el contenido de un archivo. Se diagnostica con IDs internos (instancia, app, comando, evento), estados y códigos.
  • Lo primero: Inicio y Operación en el panel, GET /health/ready, motorctl diagnostico y las métricas.
  • Los logs son JSON y ya ocultan claves, tokens mw_…, JID, teléfonos, cuerpos y query strings. Si compartes un extracto, fíltralo por instancia (el ID) y error. Nunca compartas un volcado de la base.
  • Un solo dueño de cada sesión. No levantes un segundo motor contra la misma base para «probar» (salvo el canario, que tiene su propio dominio) ni restaures una base con los mismos números en otro host sin el corte del original.
Endpoint Autenticación Responde
GET /health/live Ninguna 200 con {"estado": "ok"} mientras el proceso responde.
GET /health/ready Ninguna 200 cuando la base responde y el esquema está al día; si no, 503 con el motivo.

/health/ready trae además:

Campo Valores Qué dice
migraciones_al_dia true Las migraciones propias están al día (si no, 503).
coordinador dueno, en_espera, sin_transporte, restaurado Si este proceso tiene las sesiones, espera a que otro las suelte, arrancó sin transporte o está en modo restaurado.
multimedia configurada, deshabilitada Si hay almacenamiento en Ajustes.

Un número caído no cambia la salud del motor: no hace reiniciar el proceso. Tampoco la marca caída un proceso en espera ni la multimedia sin configurar. Los 503 posibles:

Mensaje Qué hacer
«La base de datos no responde.» Mira Postgres: La base llena.
«Hay migraciones pendientes.» Corre migrate todo.
«La base tiene migraciones más nuevas que este binario, y no son compatibles con él…» Despliega la versión nueva o restaura el backup previo (Actualizaciones).
«El store de whatsmeow no está al día: corre migrate whatsmeow.» Corre migrate whatsmeow.

El healthcheck del contenedor es motor salud: pide /health/ready al propio proceso y sale con 0 solo si responde 200.

GET /admin/api/metricas devuelve las métricas en el formato de texto de Prometheus. Pide una sesión de operador (la cookie del panel): no hay un /metrics abierto. Las etiquetas son acotadas: estado, tipo de alerta, resultado, transporte, motivo e ID técnico de la instancia; nunca teléfonos, JID ni textos.

Métrica Tipo Qué mide
motor_info gauge La versión del motor y del contrato.
motor_dueno gauge 1 si este proceso es el dueño de las sesiones.
motor_modo_restaurado gauge 1 si la base viene de un restore y el motor no abre sesiones.
motor_proceso_canario / motor_canario_bloqueado gauge Si este proceso es el canario, y si quedó bloqueado por un principal viejo.
motor_instancias{estado} / motor_instancias_caidas gauge Instancias por estado; las que quieren estar conectadas y no lo están.
motor_instancia_conectada{instancia} gauge 1 si la instancia vinculada está conectada.
motor_instancia_reconexiones_total{instancia} counter Reconexiones después de una caída.
motor_alertas_abiertas{tipo} gauge Alertas abiertas por tipo.
motor_instancias_trabadas / motor_watchdog_detecciones_total gauge / counter Lo que ve el watchdog.
motor_eventos_total{instancia,resultado} counter Eventos del socket aceptados o rechazados desde el arranque.
motor_comandos_total{resultado} counter Comandos de control completados o fallidos.
motor_conciliador_reintentos_total / motor_dueno_perdidas_total counter Reconexiones del conciliador; veces que el proceso perdió las sesiones.
motor_db_conexiones{estado} / motor_db_conexiones_max / motor_db_esperas_total gauge / counter El pool de Postgres: abiertas, en uso, ociosas, el máximo y las esperas.
motor_streams_abiertos{transporte} / motor_streams_cierres_total{motivo} gauge / counter Los streams SSE y WebSocket.
motor_backup_fallido / motor_backup_ultimo_verificado_timestamp gauge El último backup falló; la hora del último completo y verificado.
motor_proxies{estado} gauge Proxies de transporte por estado.
motor_memoria_rss_bytes / motor_memoria_bytes / motor_goroutines gauge Memoria residente, memoria pedida al sistema y goroutines.

Las alertas se ven en Inicio, en Operación y en la ficha de cada instancia (Diagnóstico). Una alerta no se duplica: si el problema sigue, suma ocurrencias. La mayoría se cierra sola cuando la causa desaparece.

Alerta Cuándo se abre Qué hacer
instancia_caida La instancia quiere estar conectada y lleva caída más que el umbral (una caída breve no alerta). Ficha → Diagnóstico: el último error y las reconexiones. Si no vuelve, Reconectar.
sesion_cerrada Se cerró la sesión de WhatsApp (desde el teléfono o porque el dispositivo ya no existe). Volver a vincular el número.
reemplazada Otro cliente tomó la sesión del número. No se reintenta sola: reconéctala a pedido.
bloqueo_temporal WhatsApp bloqueó temporalmente el número. Espera al fin del bloqueo; un intento sale al vencer.
cliente_desactualizado WhatsApp rechaza la versión del cliente. Actualiza el motor (Actualizaciones) y reconecta.
error_conexion La conexión falla. Diagnóstico de la ficha; si usa proxy, Proxy caído.
instancia_trabada Una operación remota dura más que Ajustes → Operación → Trabada después de. Instancia trabada.
proxy_caido El proxy de la instancia no conecta. Proxy caído.
entrega_suspendida Una suscripción se suspendió (el receptor respondió 401 o 403). Atraso de entregas.
presion_disco El disco temporal de la multimedia está bajo el mínimo. Libera espacio en /tmp del contenedor o súbelo; lo nuevo espera, nada se borra.
backup_fallido Falló el último backup o su verificación. Backup.
  • Inicio: el estado del motor (versión, entorno, base, migraciones, WhatsApp, multimedia), las instancias conectadas, caídas y con alertas, y los avisos (modo restaurado, disco casi lleno).
  • Operación: el proceso (dueño, canario), la memoria, las goroutines, el pool de la base, las operaciones remotas, el watchdog por instancia, el cupo de cada app, las migraciones y el último backup. Es GET /admin/api/operacion.
  • Ficha de la instancia → Diagnóstico: el estado de la sesión (abierta, conectada, autenticada), el último chequeo y el último evento, lo pendiente (comandos y webhooks), el último error, las reconexiones, el keepalive, el pool y la multimedia. Es GET /admin/api/instancias/{id}/diagnostico; una app lo ve con GET /v1/instances/{id}/diagnostics.
  • motorctl diagnostico: versión, entorno, si la clave maestra tiene el largo mínimo, la base, las migraciones y el modo, sin secretos ni datos personales.
Ventana de terminal
curl -s https://motor.ejemplo.com/health/ready
docker compose exec motor /app/motorctl diagnostico
docker compose exec motor /app/motorctl mantenimiento estado

Cada runbook del repositorio dice los síntomas, el diagnóstico y los pasos. Están en docs/runbooks/, fuera de este sitio; aquí va el resumen.

Runbook Cuándo
docs/runbooks/despliegue-coolify.md Desplegar en Coolify: los secretos generados, el primer operador, el panel por Tailscale Serve, la verificación con /health/ready, el almacenamiento, el backup y el rollback. Resumido en Despliegue y backup.
docs/runbooks/checklist-v1.0.0.md La publicación de una versión: suites, versión del binario, push, tag, Release y despliegue con el tag fijo.
docs/runbooks/backup.md Configurar, hacer, verificar y bajar un backup; un backup fallido.
docs/runbooks/restore.md Recuperar un backup en otra base, aislado, y el corte del original.
docs/runbooks/actualizacion.md Actualizar: verificación previa, canario, promoción y rollback.
docs/runbooks/instancia-trabada.md Una instancia con instancia_trabada o que no avanza.
docs/runbooks/base-llena.md La base sin espacio o cerca del límite.
docs/runbooks/minio-caido.md El almacenamiento de la multimedia (o de los backups) no responde.
docs/runbooks/rotar-clave-maestra.md Cambiar APP_MASTER_KEY, planeado o por una filtración.
docs/runbooks/proxy-caido.md Un proxy de transporte que no conecta (proxy_caido).
docs/runbooks/atraso-entregas.md Un webhook o un bridge con atraso, en la DLQ o suspendido.

docs/runbooks/backup.md

  • Síntoma: la alerta backup_fallido, motor_backup_fallido en 1, motor_backup_ultimo_verificado_timestamp de más de 24 h, o la fila «Falló» en Backups con su error (sin credenciales ni rutas internas).
  • Causa habitual: el destino (endpoint, credenciales o bucket), el destino sin configurar, o un backup que ya está en curso (409).
  • Qué hacer: corrige el destino y pulsa Probar en Ajustes → Backups hasta que dé ok; Hacer un backup ahora y Verificar. Si el destino va a seguir caído, haz uno local con motorctl backup crear --archivo /respaldos/… y cópialo fuera de la máquina (ya va cifrado).

docs/runbooks/restore.md

  • Cuándo: se perdió la base o el host, un rollback de una migración incompatible o del store de whatsmeow, o un simulacro.
  • Qué hacer: verifica el archivo, restaura en una base vacía y arranca en modo restaurado; revisa; corta el original y sal con motorctl mantenimiento salir --confirmo-corte-del-original. Detalle en Restore aislado.
  • Si falla: «la base de destino no está vacía» (usa otra), «el backup es de un esquema más nuevo» (usa un binario igual o más nuevo), «la multimedia quedó incompleta» (repite con --solo-medios).

docs/runbooks/actualizacion.md

  • Síntoma: «rollback bloqueado» al arrancar, «el canario no aplica migraciones incompatibles» o «canario bloqueado».
  • Causa: un binario viejo ante una migración incompatible, o un principal sin el protocolo de traspaso.
  • Qué hacer: no fuerces nada; restaura el backup previo o actualiza con corte. Ver Actualizaciones.

docs/runbooks/instancia-trabada.md

  • Síntoma: la alerta instancia_trabada, motor_instancias_trabadas mayor que 0, y los comandos de esa instancia en en_cola o ejecutando más de lo normal. Las demás siguen: cada número ocupa a lo sumo «Operaciones por instancia» de las simultáneas del motor.
  • Causa: una operación remota (un envío, una consulta a WhatsApp) que no avanza: WhatsApp lento, un bloqueo temporal, un proxy o la red.
  • Qué hacer: si son varias a la vez, busca la causa común (red, proxy, base). Si es una, espera: la alerta se cierra sola cuando avanza. Si sigue, Reconectar desde la ficha (queda auditado); lo que estaba en vuelo termina como enviado, fallido o ambiguo (un ambiguo nunca se reenvía solo). Si se repite, Pausar la instancia mientras se investiga.

docs/runbooks/base-llena.md

  • Síntoma: errores 500 en toda escritura («Algo falló en el motor. Intenta de nuevo.») y en el log could not extend file o No space left on device. Las lecturas siguen y /health/ready puede seguir en 200. Si Postgres deja de responder, motor_db_esperas_total sube y /health/ready pasa a 503.
  • Causa: el volumen de Postgres sin espacio. Lo que suele crecer: el ledger y las entregas, la multimedia en curso, los lotes del historial y el store de whatsmeow; un destino caído hace crecer el outbox.
  • Qué hacer: libera espacio o agranda el volumen (el motor se recupera solo cuando Postgres vuelve a escribir); baja la retención de lo entregado y de la multimedia; arregla o pausa el destino caído; después de una purga grande, VACUUM (sin FULL con el motor corriendo). Nunca borres filas a mano del ledger, del outbox ni del store.

docs/runbooks/minio-caido.md

  • Síntoma: envíos con multimedia que fallan con almacen_no_disponible (503), Probar de Ajustes → Almacenamiento con error, y backup_fallido si el destino de los backups es el mismo MinIO.
  • Causa: MinIO caído, sin espacio, o el endpoint, las credenciales o el bucket mal en Ajustes. El texto, los eventos y las entregas no dependen de él.
  • Qué hacer: levántalo o corrige Ajustes y pulsa Probar; las descargas pendientes se reanudan solas; los envíos que fallaron se reintentan desde la app. Si se perdió el bucket, la multimedia del último backup que la incluya se recupera en un restore con --subir-medios. Prevención: los backups en un bucket fuera de esta máquina.

docs/runbooks/rotar-clave-maestra.md

  • Cuándo: un cambio planeado de APP_MASTER_KEY o una filtración.
  • Lo importante: en esta versión no se puede rotar en el lugar. Cambiar la variable y reiniciar deja los secretos sin abrir, la historia ilegible y todas las keys y sesiones inválidas.
  • Qué hacer: si se filtra, evalúa qué más se expuso (la clave sola no da acceso: hace falta la base o un backup) y rota las credenciales en su origen, las keys y los secretos de los webhooks. Ver Seguridad.

docs/runbooks/proxy-caido.md

  • Síntoma: la alerta proxy_caido, motor_proxies{estado="caido"}, el proxy en «Caído» en Ajustes → Proxies con su último error saneado, y sus instancias en error_conexion o reconectando. Las demás siguen.
  • Causa: el proxy no responde, rechaza la credencial, no deja salir a WhatsApp, o su host salió de los destinos permitidos.
  • Qué hacer: Probar (abre un túnel hasta WhatsApp Web sin hablar el protocolo); arregla el proxy o su credencial; Reconectar las instancias. Si va a seguir caído, pásalas a Directa, sin proxy o a otro proxy desde la ficha → Transporte.

docs/runbooks/atraso-entregas.md

  • Síntoma: muchas entregas pendiente o fallida en Entregas; una suscripción «Suspendida» con entrega_suspendida; un bridge con atraso, en la DLQ o suspendido; un stream cortado por cliente_lento.
  • Causa: el receptor caído o lento, su host fuera de los destinos permitidos, o una credencial rechazada. El último error de cada entrega es el estado HTTP o un código: timeout, dns, conexion_rechazada, conexion_cortada, tls, red, destino_no_permitido o destino_bloqueado.
  • Qué hacer: arregla el receptor o el broker; Probar la suscripción (manda un webhook.test firmado); reactiva lo suspendido; lo pendiente sale solo; lo fallido (después de 72 h) se reenvía con un replay, con el mismo event_id. Ver Webhooks.