Heartbeat de licencia y periodo de gracia

Cómo funciona el heartbeat de licencia de Commander, qué significan los cuatro estados de gracia y cómo recuperarse de WARN o HALTED.

Si has llegado aquí desde un banner amarillo, naranja o rojo en tu panel de Commander —o desde una alerta de Telegram— esta página te explica exactamente qué está ocurriendo y qué hacer a continuación.

En resumen: tu worker de Commander en tu VPS no ha podido confirmar su licencia con runcommander.com recientemente. Tus ejecuciones no se han perdido, y en la mayoría de los casos todavía no se ha roto nada. Este documento recorre los cuatro estados en los que puede estar el sistema, las causas habituales y una prueba de un minuto que puedes lanzar para confirmar si el heartbeat nos está llegando.

Los cuatro estados del heartbeat

Cada worker de Commander llama a casa en un intervalo corto y registra la hora de su última respuesta correcta. A partir de esa marca temporal, el worker deriva uno de cuatro estados. El estado determina cómo se comporta el worker y qué banner ves.

OK

Último heartbeat exitoso: hace menos de 24 horas.

Es el estado normal. Las ejecuciones arrancan y terminan según lo programado. No verás ningún banner ni alerta. Nada que hacer por tu parte.

WARN_1 — amarillo

Último heartbeat exitoso: entre 24 y 48 horas atrás.

El worker sigue plenamente operativo. Las ejecuciones continúan arrancando y completándose con normalidad. El banner amarillo es informativo —queremos que sepas que llevamos un día sin saber de tu worker, para que puedas investigar cuando te venga bien. El worker sigue reintentando automáticamente en segundo plano. Si el siguiente heartbeat funciona, el banner desaparece de inmediato.

WARN_2 — naranja

Último heartbeat exitoso: entre 48 y 72 horas atrás.

Mismo comportamiento operativo que WARN_1 —las ejecuciones continúan con normalidad— pero el tono se intensifica. A las 72 horas, el worker se negará a iniciar nuevas ejecuciones. Las que estén en curso se terminarán igualmente. Esta es tu última advertencia para actuar antes de que ocurra. La mayoría de los casos a estas alturas son problemas de red o DNS desatendidos en el VPS que son fáciles de arreglar una vez detectados.

HALTED — rojo

Último heartbeat exitoso: 72 horas o más atrás.

El worker no iniciará nuevas ejecuciones. Las ejecuciones que ya estaban en marcha cuando se produjo el cambio de estado continúan hasta terminar —Commander nunca mata trabajo a mitad de camino. En cuanto un solo heartbeat vuelva a funcionar, el estado se limpia atómicamente y las nuevas ejecuciones se reanudan en el siguiente tick programado. No hace falta ningún desbloqueo manual ni hay periodo de penalización.

Causas habituales

En orden aproximado de frecuencia, esto es lo que suele provocar que un heartbeat falle:

  • Microcorte de red en el VPS. Pérdida transitoria de paquetes, una breve caída del proveedor del VPS o un fallo puntual de DNS. La mayoría se recuperan solos en minutos; puede que veas WARN_1 brevemente y luego nada más.
  • Cambio en el firewall o en las reglas de salida. Alguien añadió un bloqueo de salida, un nuevo grupo de seguridad o una regla de UFW que ya no permite HTTPS hacia runcommander.com. Habitual justo después de un endurecimiento o una migración del servidor.
  • Token de licencia caducado o rotado. Si tu token se rotó en el panel pero el valor nuevo nunca llegó a ~/.commander/license.token en el VPS, cada heartbeat fallará la autenticación. Revisa los logs del worker buscando una respuesta 401.
  • Fallo de facturación. Si tu suscripción venció, el servidor de licencias rechazará los heartbeats con una respuesta clara state: REVOKED. Tu panel de Commander mostrará directamente el problema de facturación —corrige el método de pago y la licencia se reactiva en segundos.
  • Reloj desfasado en el VPS. Poco común, pero un VPS con el reloj desfasado más de unos minutos puede romper el handshake TLS contra nuestro edge. timedatectl status te lo dirá.

Probar el heartbeat manualmente

Si tienes acceso por shell al VPS donde corre tu worker de Commander, esta prueba de un minuto confirma si el ida y vuelta del heartbeat funciona de extremo a extremo. Usa el mismo token y fingerprint que usa el worker.

# 1. Obtén tu token de licencia almacenado
cat ~/.commander/license.token

# 2. Obtén el fingerprint de tu worker
cat ~/.commander/fingerprint

# 3. Envíalo al servidor de licencias por POST
curl -sX POST \
  -H "authorization: Bearer $(cat ~/.commander/license.token)" \
  -H "content-type: application/json" \
  -d "{\"fingerprint\":\"$(cat ~/.commander/fingerprint)\",\"agentVersion\":\"0.0.1\"}" \
  https://runcommander.com/api/license/heartbeat | jq .

# Esperado: { "ok": true, "state": "OK", "secondsSinceLastSuccess": 0, ... }

Interpreta el resultado:

  • Una respuesta con "ok": true y "state": "OK" significa que el ida y vuelta funciona. El worker debería limpiar su estado de advertencia en el siguiente heartbeat programado. Si el banner persiste más de unos minutos después, reinicia el proceso del worker.
  • Una respuesta con "ok": false incluirá un motivo. Los dos habituales son "reason": "invalid_token" (rota el token desde el panel y actualiza ~/.commander/license.token) y "reason": "revoked" (revisa Facturación en el panel).
  • Un error de red o un cuelgue significa que el VPS no puede alcanzar runcommander.com por HTTPS en absoluto. Prueba con curl -v https://runcommander.com/api/health para ver si el fallo es de DNS, TCP o TLS, y revisa tus reglas de salida.

Cuándo contactar con soporte

Escribe a hello@dekimu.com si se cumple alguna de estas condiciones:

  • El curl manual de arriba devuelve "ok": true pero el banner del panel no se limpia en menos de 10 minutos.
  • Tu estado de Facturación está al día y el servidor de licencias sigue respondiendo con "reason": "revoked".
  • Ves un valor de state que no es ninguno de OK, WARN_1, WARN_2, HALTED o REVOKED.
  • Los logs del worker muestran heartbeats exitosos pero las ejecuciones en curso se están matando (esto nunca debería ocurrir —Commander siempre drena).

Incluye en tu primer mensaje la salida de la prueba manual con curl y las últimas 50 líneas del log del worker. Suele ser suficiente para que identifiquemos la causa sin necesidad de un intercambio largo.