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.
Reglas para diagnosticar
Sección titulada «Reglas para diagnosticar»- 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 diagnosticoy 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 porinstancia(el ID) yerror. 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.
Métricas
Sección titulada «Métricas»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. |
Alertas
Sección titulada «Alertas»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. |
Diagnóstico
Sección titulada «Diagnóstico»- 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 conGET /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.
curl -s https://motor.ejemplo.com/health/readydocker compose exec motor /app/motorctl diagnosticodocker compose exec motor /app/motorctl mantenimiento estadoLos runbooks
Sección titulada «Los runbooks»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_fallidoen 1,motor_backup_ultimo_verificado_timestampde 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).
Restore
Sección titulada «Restore»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).
Actualización
Sección titulada «Actualización»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.
Instancia trabada
Sección titulada «Instancia trabada»docs/runbooks/instancia-trabada.md
- Síntoma: la alerta
instancia_trabada,motor_instancias_trabadasmayor que 0, y los comandos de esa instancia enen_colaoejecutandomá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,fallidooambiguo(un ambiguo nunca se reenvía solo). Si se repite, Pausar la instancia mientras se investiga.
La base llena
Sección titulada «La base llena»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 fileoNo space left on device. Las lecturas siguen y/health/readypuede seguir en 200. Si Postgres deja de responder,motor_db_esperas_totalsube y/health/readypasa 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(sinFULLcon el motor corriendo). Nunca borres filas a mano del ledger, del outbox ni del store.
MinIO caído
Sección titulada «MinIO caído»docs/runbooks/minio-caido.md
- Síntoma: envíos con multimedia que fallan con
almacen_no_disponible(503), Probar de Ajustes → Almacenamiento con error, ybackup_fallidosi 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.
Rotar la clave maestra
Sección titulada «Rotar la clave maestra»docs/runbooks/rotar-clave-maestra.md
- Cuándo: un cambio planeado de
APP_MASTER_KEYo 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.
Proxy caído
Sección titulada «Proxy caído»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 enerror_conexiono 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.
Atraso de entregas
Sección titulada «Atraso de entregas»docs/runbooks/atraso-entregas.md
- Síntoma: muchas entregas
pendienteofallidaen Entregas; una suscripción «Suspendida» conentrega_suspendida; un bridge con atraso, en la DLQ o suspendido; un stream cortado porcliente_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_permitidoodestino_bloqueado. - Qué hacer: arregla el receptor o el broker; Probar la suscripción (manda un
webhook.testfirmado); reactiva lo suspendido; lo pendiente sale solo; lo fallido (después de 72 h) se reenvía con un replay, con el mismoevent_id. Ver Webhooks.