fix(tmux-host): lanzar claude al recrear la sesion + backoff de arranque
check_tmux_session() recreaba la sesion tmux "lab" tras un reinicio del NAS pero nunca lanzaba `claude` adentro -- quedaba un shell vacio hasta que alguien entraba a mano. Confirmado en vivo tras un corte de luz real (2026-09-19): la sesion SI se recreaba sola, pero Claude Code no. Se agrega wait_for_workdir() con backoff (hasta 120s por defecto) antes de tocar el log o crear la sesion, para el caso de un reinicio completo del host donde /media/HDD-Storage puede tardar en montarse mas de lo que tarda Docker en arrancar este contenedor -- antes eso fallaba en silencio y ese arranque no dejaba rastro en el log. Probado en un contenedor descartable aparte (tmux-host-test): stop+start desde cero recreo la sesion con claude corriendo, sin intervencion. Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
1 parent
9d04c73b20
commit
955eec6e75
1 file changed
+59
-3
@@ -11,7 +11,9 @@
|
||||
# b) Existencia de la sesion tmux "lab". Si no existe (crash, o el
|
||||
# contenedor se acaba de recrear), SI se recrea automaticamente --
|
||||
# es solo recuperar el propio entorno de trabajo, no tocar
|
||||
# infraestructura externa.
|
||||
# infraestructura externa. Al recrearla tambien se lanza `claude`
|
||||
# adentro (ver launch_claude_in_session) -- una sesion recreada sin
|
||||
# esto es un shell pelado, no "el entorno de trabajo".
|
||||
#
|
||||
# Todo evento (chequeo ok, falla, accion tomada) queda en LOG_FILE, que
|
||||
# vive bajo /DATA (persistente, sobrevive a recrear el contenedor) y no
|
||||
@@ -31,13 +33,42 @@ LOG_FILE="${LOG_DIR}/health.log"
|
||||
LAB_AGENT_ENV="${WORKDIR}/scripts/lab-agent/lab-agent.env"
|
||||
NETWORK_CHECK_URL="https://gitea.cruzcloud.net/"
|
||||
INTERVAL_SEC="${HEALTHCHECK_INTERVAL_SEC:-1800}"
|
||||
# Cuanto esperar, SOLO al arrancar, a que WORKDIR este disponible antes de
|
||||
# tocarlo. Tras un `docker restart` normal el host y sus mounts ya estaban
|
||||
# arriba; tras un reinicio COMPLETO del NAS (corte de luz), Docker puede
|
||||
# arrancar este contenedor antes de que /media/HDD-Storage termine de
|
||||
# montarse en el host -- y WORKDIR llega a el via el symlink absoluto
|
||||
# /DATA/AppData -> /media/HDD-Storage/AppData (ver el gotcha del symlink en
|
||||
# docs-portal/docs/arquitectura/sesion-tmux-persistente.md). Sin esta
|
||||
# espera, `mkdir -p "$LOG_DIR"` de mas abajo fallaba en silencio (set -u sin
|
||||
# -e) y ese arranque quedaba SIN NINGUN rastro en el log -- asi se paso por
|
||||
# alto originalmente el gotcha de "no lanzo claude" reportado 2026-09-19.
|
||||
STARTUP_MOUNT_WAIT_MAX_SEC="${STARTUP_MOUNT_WAIT_MAX_SEC:-120}"
|
||||
STARTUP_MOUNT_WAIT_STEP_SEC=5
|
||||
|
||||
mkdir -p "$LOG_DIR"
|
||||
wait_for_workdir() {
|
||||
local waited=0
|
||||
while [[ ! -d "$WORKDIR" ]] && [[ "$waited" -lt "$STARTUP_MOUNT_WAIT_MAX_SEC" ]]; do
|
||||
sleep "$STARTUP_MOUNT_WAIT_STEP_SEC"
|
||||
waited=$((waited + STARTUP_MOUNT_WAIT_STEP_SEC))
|
||||
done
|
||||
echo "$waited"
|
||||
}
|
||||
|
||||
STARTUP_WAITED_SEC="$(wait_for_workdir)"
|
||||
|
||||
mkdir -p "$LOG_DIR" 2>/dev/null || true
|
||||
|
||||
log() {
|
||||
echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] $*" >> "$LOG_FILE"
|
||||
echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] $*" >> "$LOG_FILE" 2>/dev/null || true
|
||||
}
|
||||
|
||||
if [[ ! -d "$WORKDIR" ]]; then
|
||||
log "ARRANQUE: ERROR -- ${WORKDIR} sigue sin existir tras esperar ${STARTUP_MOUNT_WAIT_MAX_SEC}s. El mount de /DATA o /media/HDD-Storage del host no esta listo; revisar fuera del contenedor."
|
||||
elif [[ "$STARTUP_WAITED_SEC" -gt 0 ]]; then
|
||||
log "ARRANQUE: ${WORKDIR} tardo ${STARTUP_WAITED_SEC}s en estar disponible (probable reinicio completo del host reordenando el montaje de /DATA)."
|
||||
fi
|
||||
|
||||
notify_telegram() {
|
||||
local title="$1" message="$2"
|
||||
if [[ ! -f "$LAB_AGENT_ENV" ]]; then
|
||||
@@ -73,14 +104,39 @@ check_network() {
|
||||
fi
|
||||
}
|
||||
|
||||
launch_claude_in_session() {
|
||||
# El pane recien creado tarda un instante en tener su shell listo para
|
||||
# recibir input -- un send-keys inmediato a veces se pierde. 1s alcanza
|
||||
# sobrado para un shell interactivo local (no depende de red).
|
||||
sleep 1
|
||||
if tmux send-keys -t "$SESSION" "claude" Enter 2>>"$LOG_FILE"; then
|
||||
log "TMUX: 'claude' lanzado dentro de la sesion recien creada"
|
||||
else
|
||||
log "TMUX: ERROR al lanzar 'claude' dentro de la sesion recien creada"
|
||||
fi
|
||||
}
|
||||
|
||||
check_tmux_session() {
|
||||
if tmux has-session -t "$SESSION" 2>/dev/null; then
|
||||
log "TMUX: sesion '${SESSION}' ok"
|
||||
return
|
||||
fi
|
||||
if [[ ! -d "$WORKDIR" ]]; then
|
||||
# No se crea sobre un WORKDIR ausente (quedaria posicionada en /). Se
|
||||
# reintenta en el proximo ciclo -- ver STARTUP_MOUNT_WAIT_MAX_SEC arriba
|
||||
# para el caso especifico de arranque en frio del host.
|
||||
log "TMUX: sesion '${SESSION}' no existe y ${WORKDIR} tampoco -- no se crea esta vuelta, se reintenta en el proximo ciclo (${INTERVAL_SEC}s)."
|
||||
return
|
||||
fi
|
||||
log "TMUX: sesion '${SESSION}' no existe -- recreando en ${WORKDIR}"
|
||||
if tmux new-session -d -s "$SESSION" -c "$WORKDIR" 2>>"$LOG_FILE"; then
|
||||
log "TMUX: sesion '${SESSION}' recreada exitosamente"
|
||||
# Una sesion recreada sin esto es un shell vacio hasta que alguien
|
||||
# entre a mano y escriba "claude" -- exactamente el gotcha reportado
|
||||
# tras el reinicio completo del NAS del 2026-09-18/19: la sesion SI se
|
||||
# recreaba sola (confirmado en el log de ese arranque), pero Claude
|
||||
# Code nunca arrancaba adentro.
|
||||
launch_claude_in_session
|
||||
else
|
||||
log "TMUX: ERROR al recrear la sesion '${SESSION}'"
|
||||
fi
|
||||
|
||||
Reference in new issue
Block a user