Anade tambien como leer por que rama fue una ejecucion cuando EXECUTIONS_DATA_SAVE_ON_SUCCESS=none ya la ha vaciado: por la duracion. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
5.0 KiB
Notas para agentes que trabajan en este cluster
Este es el directorio de trabajo de Hermes (el agente de Telegram) y de
cualquier sesión de Claude Code sobre el homelab. Aquí van solo las cosas que
engañan al mirarlas: lo que parece una avería y no lo es, y lo que parece
inofensivo y no lo es. Lo demás está en el skill k8s-infra.
n8n: las ejecuciones «running» que nunca terminan NO están colgadas
Desde el 2026-07-30 el deployment lleva EXECUTIONS_DATA_SAVE_ON_SUCCESS=none.
Cuando un workflow sale bien, n8n crea igualmente la fila en
execution_entity, le pone deletedAt al instante y no actualiza el estado,
porque la va a tirar. El barrido duro se las lleva cada ~15 min.
O sea que SELECT ... FROM execution_entity enseña filas con
status='running' y stoppedAt=NULL que son ejecuciones exitosas ya
borradas. No hay nada que arreglar. Ya provocó un diagnóstico en falso el
mismo día que se puso.
Para saber si un workflow corre de verdad, mirar workflow_statistics:
SELECT name, count FROM workflow_statistics WHERE workflowId='<id>';
-- production_success sube en cada vuelta aunque la ejecución no se guarde
Sale también en deletedAt IS NOT NULL. Y ojo: startedAt y deletedAt no
llevan el mismo huso, así que restarlas no significa nada.
n8n: lo que se ejecuta es la versión PUBLICADA, no el borrador
workflow_entity.nodes es el borrador. Producción usa la versión de
workflow_history apuntada por workflow_entity.activeVersionId. Editar
nodes a mano y reiniciar no cambia nada y no da ningún error. La API
pública (PUT /api/v1/workflows/{id}) sí publica; parcheando SQLite hay que
escribir en las dos tablas.
Diagnóstico rápido: comparar las dos columnas. Si difieren, lo que corre no es lo que estás leyendo.
Antes de tocar una BD de un pod: desarmar ArgoCD
Casi todo está bajo Applications con automated{selfHeal,prune}. Un
kubectl scale --replicas=0 para hacer un VACUUM se revierte solo a mitad.
kubectl -n argocd patch app <app> --type json \
-p '[{"op":"remove","path":"/spec/syncPolicy/automated"}]'
# ... trabajo ...
kubectl -n argocd patch app <app> --type merge \
-p '{"spec":{"syncPolicy":{"automated":{"prune":true,"selfHeal":true}}}}'
Rearmarlo al final levanta el pod y aplica la config nueva de una vez.
ArgoCD: una Application de directorio se traga los .json
path: n8n incluye *.yaml, *.yml y *.json como manifiestos. Un JSON
que no sea un objeto de Kubernetes deja la app en ComparisonError («Object
'Kind' is missing»). Por eso application-n8n.yaml tiene
directory.exclude: "workflow-*.json". Los .md no se parsean: este fichero es
seguro.
El auto-reinicio de Uptime Kuma sí funciona (desde 2026-07-30) y va cerrado
Kuma cae → notificación «n8n Auto-Restart» → webhook público de n8n → PATCH del
restartedAt. Antes no reiniciaba nada (sin RBAC: 403), y sus «éxitos» eran el
aviso de FALLO enviándose bien.
- La SA es
n8n-restarter. Desde el 2026-07-31 son Roles por namespace conresourceNamessobre los 12 workloads exactos delSERVICE_MAP(vern8n/rbac-restarter.yaml), no un ClusterRole abierto. Si añades un servicio al mapa, hay que añadirlo también ahí o dará 403 — deliberado: el mapa y el permiso se mueven juntos. Motivo: esa SA va montada en el pod entero de n8n y los nodos Code leen el token de/var/run/secrets/…, así que cualquier workflow con un nodo Code hereda lo que se conceda aquí. El límite no es el mapa, es el RBAC. - La clave del mapa es el nombre exacto del monitor en Kuma. Renombrarlo allí lo desconecta en silencio.
- El webhook exige la cabecera
X-Kuma-Token(secretn8n-kuma-webhook, fuera de git) y desde el 2026-07-31 falla en CERRADO: elenvya no llevaoptional, así que sin secreto el pod no arranca, y la puerta lanza error si la variable falta. Antes se saltaba la comprobación «para no quedarte sin avisos», y ese argumento era falso: el aviso de caída lo manda Kuma por su notificación 1, directa, no por este webhook. - Para apps bajo ArgoCD, el
restartedAtse revierte tras el reinicio. El pod sí se reinicia; la anotación no queda. No es un fallo. Por eso el éxito se comprueba conobservedGeneration >= la generation que devolvió el PATCH, y con>=y no con==: la reversión vuelve a subir la generation. - Cómo saber por qué rama fue una ejecución cuando
SAVE_ON_SUCCESS=noneya la ha vaciado: por la duración.deletedAt - startedAt(con el offset fijo de 1 h) da ~0,02 s si la puerta rechazó, ~0,3 s si el PATCH falló y se fue por la rama de fallo, y ~60 s si hizo el ciclo completo con su espera.
Un workflow que termina en verde no dice que haya hecho su trabajo
Vale para n8n y para cualquier automatismo de aquí: comprobar el efecto
(que el restartedAt cambió, que el pod es nuevo, que el fichero está), no el
código de salida ni el contador de éxitos.