granja: el worker rehacía 87 de 90 recetas por ciclo — el sync del store es de UN SOLO SENTIDO
Fui a mirar los fallos de la granja y el número no cuadraba: de 20 «fallos» de incoming-gnome, 17 correspondían a recetas CON ARTEFACTO VIGENTE en el hub. Primero pensé que eran marcadores `.fail` rancios, y me equivoqué: `build-farm.sh` hace `rm -rf "$FARM"` al empezar cada ciclo, así que el status es siempre del ciclo actual. Después pensé que el worker corría recetas viejas, y también me equivoqué: comparados los md5, hub y worker tienen copias IDÉNTICAS. LA CAUSA REAL está en `farm-sync.sh`: sube el código EXCLUYENDO /store y baja el store del worker. El store viaja worker→hub y nunca hub→worker. O sea que **el worker no se entera de nada de lo que se sella en el hub**, y cada ciclo reintenta —y vuelve a fallar— trabajo ya hecho. Medido: de las 90 recetas de incoming-gnome, **87 ya están selladas en el hub**. El worker estaba quemando el 97% de esa cola en repetir lo hecho. EL ARREGLO no es mandarle los artefactos (gigabytes por un enlace de 8 Mbps) sino la LISTA: `work/farm-sellados.txt` son los nombres `<hash>-<paquete>` del store del hub, unos kilobytes. `farm-sync.sh` la regenera en cada sync (para que no envejezca sola) y `build-farm.sh` salta la receta cuyo hash vigente ya esté ahí. Ojo al detalle de rsync: la subida excluye /work, así que el manifiesto necesita un `--include` ANTES del `--exclude` — rsync aplica la primera regla que casa, y sin ese orden el fichero no viajaba y el arreglo no habría hecho nada en silencio. Y LAS TRES DEUDAS REALES DE LA GRANJA SON UNA. gnome-session, gnome-settings-daemon y gdm mueren todas en GTK3, que el frente GNOME aparcó a propósito. Verificado contra el meson.build de cada tag: gnome-session 48.0 lo pide incondicional; gnome-settings-daemon 48.1 pide gtk+-3.0 Y gtk+-x11-3.0 (dos de las tres deudas aparcadas, no una); gdm 48.0 lo tiene condicionado a `if have_xdmcp` pero da igual, porque muere construyendo gnome-session. De paso, gnome-session pasaba `-Dsystemd=false -Dsystemd_journal=false`, dos opciones que NO EXISTEN en 48.0 (sus opciones reales son seis: deprecation_flags, session_selector, systemduserunitdir, docbook, man, x11). Meson aborta en la primera opción desconocida, así que la receta ni llegaba a configurar y el fallo real quedaba tapado. Corregido, más -Dx11=false. El diagnóstico de fondo YA ESTABA en la receta desde el 2026-07-27 y era más completo que el mío (dice GTK3 **y** libsystemd); quité la nota duplicada que había añadido. Y en el respaldo: la comprobación inicial de SSH era de un solo intento y tiró la corrida al relanzarlo llegando a casa, con el wifi aún sin levantar. Es el peor momento para rendirse — quien relanza un respaldo interrumpido acaba de cambiar de red. Ahora reintenta. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,19 @@
|
|||||||
# arje-logind-compat (D-Bus, ya sellado). gdm se apoya en ESE login1. Por eso -Dsystemd=false y el
|
# arje-logind-compat (D-Bus, ya sellado). gdm se apoya en ESE login1. Por eso -Dsystemd=false y el
|
||||||
# soporte de sesión va por el shim. (NO es frontera: login1 está cubierto.)
|
# soporte de sesión va por el shim. (NO es frontera: login1 está cubierto.)
|
||||||
# Feature-minimal: plymouth/selinux/systemd-journal off; Wayland-only (sin X11). El greeter es GNOME.
|
# Feature-minimal: plymouth/selinux/systemd-journal off; Wayland-only (sin X11). El greeter es GNOME.
|
||||||
|
#
|
||||||
|
# ── 🧱 BLOQUEADA POR GTK3, QUE ESTÁ APARCADO POR DISEÑO (medido 2026-08-07) ─────────────────────
|
||||||
|
# Las TRES recetas que quedaban en deuda en la granja (gnome-session, gnome-settings-daemon, gdm)
|
||||||
|
# NO son tres problemas: son UNO. Todas mueren en GTK3, que es una de las tres deudas que el frente
|
||||||
|
# GNOME aparcó a propósito (GTK3 / X11 / PAM). Verificado contra el `meson.build` de cada tag:
|
||||||
|
# · gnome-session 48.0 → `gtk_dep = dependency('gtk+-3.0')` en el nivel superior, sin `if`.
|
||||||
|
# · gnome-settings-daemon 48.1→ gtk+-3.0 **y `gtk+-x11-3.0`**, ambos incondicionales ⇒ bloqueada
|
||||||
|
# por DOS de las tres deudas aparcadas, no por una.
|
||||||
|
# · gdm 48.0 → su gtk+-3.0 sí es condicional (`if have_xdmcp`, y xdmcp es opción),
|
||||||
|
# pero da igual: depende de gnome-session y muere construyéndola.
|
||||||
|
# ⇒ No reintentar estas tres esperando que cambie algo. Se destraban el día que entre GTK3 (y para
|
||||||
|
# gnome-settings-daemon, también X11), no antes. Es una decisión de alcance, no un fallo.
|
||||||
|
|
||||||
name = "gdm"
|
name = "gdm"
|
||||||
version = "48.0"
|
version = "48.0"
|
||||||
license = "GPL-2.0-or-later"
|
license = "GPL-2.0-or-later"
|
||||||
|
|||||||
@@ -5,6 +5,10 @@
|
|||||||
# Esta distro NO usa systemd: el login1 lo provee arje-logind-compat (D-Bus), el init es arje-zero.
|
# Esta distro NO usa systemd: el login1 lo provee arje-logind-compat (D-Bus), el init es arje-zero.
|
||||||
# Feature-minimal: -Dsystemd=false -Dsystemd_journal=false (sin dep de libsystemd), docs/man off.
|
# Feature-minimal: -Dsystemd=false -Dsystemd_journal=false (sin dep de libsystemd), docs/man off.
|
||||||
# gnome-session usa gtk4 para el diálogo de fallo ("failwhale") y json-glib para el perfil de sesión.
|
# gnome-session usa gtk4 para el diálogo de fallo ("failwhale") y json-glib para el perfil de sesión.
|
||||||
|
#
|
||||||
|
# ⛔ APARCADA: el diagnóstico completo está más abajo, junto a `[deps]` (GTK3 **y** libsystemd, los
|
||||||
|
# dos incondicionales). Lo confirmado el 2026-08-07 no lo cambia; sólo añade que la granja seguía
|
||||||
|
# reintentándola, que es un problema de COLA, no de receta.
|
||||||
name = "gnome-session"
|
name = "gnome-session"
|
||||||
version = "48.0"
|
version = "48.0"
|
||||||
license = "GPL-2.0-or-later"
|
license = "GPL-2.0-or-later"
|
||||||
@@ -19,7 +23,19 @@ target = "x86_64-linux-musl"
|
|||||||
link = "static"
|
link = "static"
|
||||||
|
|
||||||
[build.phases]
|
[build.phases]
|
||||||
configure = "PKG_CONFIG_PATH=/usr/lib/pkgconfig PYTHONPATH=/usr/lib/python3.12/site-packages meson setup output --prefix=/usr --buildtype=release --wrap-mode=nodownload --prefer-static -Ddefault_library=static -Dsystemd=false -Dsystemd_journal=false -Ddocbook=false -Dman=false -Dc_args=-Wno-error=date-time"
|
# ── `-Dsystemd=false -Dsystemd_journal=false` NO EXISTEN en 48.0 y mataban el build ────────────
|
||||||
|
# Fallaba con `meson.build:1:0: ERROR: Unknown option: "systemd"`. Comprobado contra el
|
||||||
|
# `meson_options.txt` del tag 48.0, las opciones REALES son exactamente seis:
|
||||||
|
# deprecation_flags · session_selector · systemduserunitdir · docbook · man · x11
|
||||||
|
# O sea que el soporte de systemd dejó de ser una perilla booleana; lo único que queda de systemd es
|
||||||
|
# `systemduserunitdir`, que es una RUTA, no un interruptor. Pasar perillas que no existen no es
|
||||||
|
# inofensivo: meson aborta en la primera, así que la receta nunca llegó a configurar.
|
||||||
|
# ⇒ Lección: una opción `-D` inventada no se ignora, mata el build. Verificar contra el
|
||||||
|
# `meson_options.txt` DEL TAG que la receta pinea, no contra la memoria de otra versión.
|
||||||
|
#
|
||||||
|
# `-Dx11=false`: la imagen es Wayland pura y el default de esa opción es `true`, que arrastraría la
|
||||||
|
# torre de X11 que deliberadamente no tenemos (ver la deuda aparcada de GTK3/X11/PAM del frente).
|
||||||
|
configure = "PKG_CONFIG_PATH=/usr/lib/pkgconfig PYTHONPATH=/usr/lib/python3.12/site-packages meson setup output --prefix=/usr --buildtype=release --wrap-mode=nodownload --prefer-static -Ddefault_library=static -Dx11=false -Ddocbook=false -Dman=false -Dc_args=-Wno-error=date-time"
|
||||||
compile = "PYTHONPATH=/usr/lib/python3.12/site-packages ninja -C output"
|
compile = "PYTHONPATH=/usr/lib/python3.12/site-packages ninja -C output"
|
||||||
install = "PYTHONPATH=/usr/lib/python3.12/site-packages DESTDIR=/out meson install -C output --no-rebuild"
|
install = "PYTHONPATH=/usr/lib/python3.12/site-packages DESTDIR=/out meson install -C output --no-rebuild"
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,19 @@
|
|||||||
# NO BLOQUEA EL ESCRITORIO: gnome-shell no depende de g-s-d ni en build ni para arrancar; sin él la
|
# NO BLOQUEA EL ESCRITORIO: gnome-shell no depende de g-s-d ni en build ni para arrancar; sin él la
|
||||||
# sesión sube y lo que se pierde son las teclas de medios, la gestión de energía y el perfil de color
|
# sesión sube y lo que se pierde son las teclas de medios, la gestión de energía y el perfil de color
|
||||||
# (los aplica este daemon, no el shell). Es degradación, no ausencia de escritorio.
|
# (los aplica este daemon, no el shell). Es degradación, no ausencia de escritorio.
|
||||||
|
#
|
||||||
|
# ── 🧱 BLOQUEADA POR GTK3, QUE ESTÁ APARCADO POR DISEÑO (medido 2026-08-07) ─────────────────────
|
||||||
|
# Las TRES recetas que quedaban en deuda en la granja (gnome-session, gnome-settings-daemon, gdm)
|
||||||
|
# NO son tres problemas: son UNO. Todas mueren en GTK3, que es una de las tres deudas que el frente
|
||||||
|
# GNOME aparcó a propósito (GTK3 / X11 / PAM). Verificado contra el `meson.build` de cada tag:
|
||||||
|
# · gnome-session 48.0 → `gtk_dep = dependency('gtk+-3.0')` en el nivel superior, sin `if`.
|
||||||
|
# · gnome-settings-daemon 48.1→ gtk+-3.0 **y `gtk+-x11-3.0`**, ambos incondicionales ⇒ bloqueada
|
||||||
|
# por DOS de las tres deudas aparcadas, no por una.
|
||||||
|
# · gdm 48.0 → su gtk+-3.0 sí es condicional (`if have_xdmcp`, y xdmcp es opción),
|
||||||
|
# pero da igual: depende de gnome-session y muere construyéndola.
|
||||||
|
# ⇒ No reintentar estas tres esperando que cambie algo. Se destraban el día que entre GTK3 (y para
|
||||||
|
# gnome-settings-daemon, también X11), no antes. Es una decisión de alcance, no un fallo.
|
||||||
|
|
||||||
name = "gnome-settings-daemon"
|
name = "gnome-settings-daemon"
|
||||||
version = "48.1"
|
version = "48.1"
|
||||||
license = "GPL-2.0-or-later"
|
license = "GPL-2.0-or-later"
|
||||||
|
|||||||
@@ -35,6 +35,30 @@ rm -rf "$FARM"; mkdir -p "$FARM/log" "$FARM/status"
|
|||||||
|
|
||||||
queue=$(ls "$QUEUE"/*.toml 2>/dev/null || true)
|
queue=$(ls "$QUEUE"/*.toml 2>/dev/null || true)
|
||||||
[ -n "$queue" ] || { echo "cola vacía: $QUEUE/*.toml"; exit 0; }
|
[ -n "$queue" ] || { echo "cola vacía: $QUEUE/*.toml"; exit 0; }
|
||||||
|
|
||||||
|
# ── NO REHACER LO QUE EL HUB YA SELLÓ ──────────────────────────────────────────────────────────
|
||||||
|
# `farm-sync.sh` sincroniza el store en UN SOLO SENTIDO: sube el código EXCLUYENDO /store y baja el
|
||||||
|
# store del worker. O sea que el worker nunca recibe los artefactos que se sellan en el hub — y por
|
||||||
|
# tanto reintenta cada ciclo, y vuelve a fallar, trabajo que YA ESTÁ HECHO. Medido el 2026-08-07:
|
||||||
|
# de 20 «fallos» de incoming-gnome, 17 correspondían a recetas con artefacto vigente en el hub.
|
||||||
|
# No eran marcadores rancios (el status se borra en cada ciclo): era CPU quemada de verdad.
|
||||||
|
#
|
||||||
|
# Mandarle los artefactos costaría gigabytes por un enlace de 8 Mbps. Mandarle la LISTA cuesta unos
|
||||||
|
# kilobytes: `work/farm-sellados.txt` son los nombres `<hash>-<paquete>` del store del hub. Si el
|
||||||
|
# hash vigente de una receta está ahí, el hub ya la tiene y el worker se la salta.
|
||||||
|
SELLADOS="${SELLADOS:-work/farm-sellados.txt}"
|
||||||
|
if [ -s "$SELLADOS" ]; then
|
||||||
|
saltadas=0; filtrada=""
|
||||||
|
for f in $queue; do
|
||||||
|
n=$(basename "$f" .toml)
|
||||||
|
H=$("$HAMMER" --store "$STORE" hash "$f" 2>/dev/null | tail -1 | sed 's/^b3://')
|
||||||
|
if [ -n "$H" ] && grep -qx "$H-$n" "$SELLADOS"; then saltadas=$((saltadas+1)); continue; fi
|
||||||
|
filtrada="$filtrada $f"
|
||||||
|
done
|
||||||
|
[ "$saltadas" -gt 0 ] && echo " (saltadas $saltadas ya selladas en el hub — ver la nota del sync unidireccional)"
|
||||||
|
queue="$filtrada"
|
||||||
|
[ -n "$(echo $queue)" ] || { echo "nada que hacer en $QUEUE: todo sellado en el hub"; exit 0; }
|
||||||
|
fi
|
||||||
n_total=$(printf '%s\n' "$queue" | wc -l | tr -d ' ')
|
n_total=$(printf '%s\n' "$queue" | wc -l | tr -d ' ')
|
||||||
echo "==> GRANJA: $n_total recetas en $QUEUE, $JOBS workers en paralelo"
|
echo "==> GRANJA: $n_total recetas en $QUEUE, $JOBS workers en paralelo"
|
||||||
|
|
||||||
|
|||||||
@@ -19,8 +19,18 @@ ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
|
|||||||
cd "$ROOT"
|
cd "$ROOT"
|
||||||
SSH="ssh -i $SSH_KEY -o StrictHostKeyChecking=accept-new"
|
SSH="ssh -i $SSH_KEY -o StrictHostKeyChecking=accept-new"
|
||||||
|
|
||||||
|
# El MANIFIESTO de lo ya sellado en el hub, para que el worker no rehaga trabajo hecho. Es la otra
|
||||||
|
# mitad del arreglo del sync unidireccional (ver la nota en `scripts/build-farm.sh`): el store no
|
||||||
|
# viaja hub→worker porque son gigabytes, pero la lista de nombres son kilobytes y evita que el worker
|
||||||
|
# reintente y falle cada ciclo lo que el hub ya tiene. Se regenera acá, en cada sync, para que no se
|
||||||
|
# quede vieja sola.
|
||||||
|
mkdir -p work
|
||||||
|
ls ./store 2>/dev/null | grep -E '^[0-9a-f]{64}-' > work/farm-sellados.txt || true
|
||||||
|
echo "==> 0. manifiesto de sellados del hub: $(wc -l < work/farm-sellados.txt) artefactos"
|
||||||
|
|
||||||
echo "==> 1. subiendo código + cola al worker ($VPS:$REMOTE)"
|
echo "==> 1. subiendo código + cola al worker ($VPS:$REMOTE)"
|
||||||
rsync -az --delete -e "$SSH" \
|
rsync -az --delete -e "$SSH" \
|
||||||
|
--include '/work/' --include '/work/farm-sellados.txt' \
|
||||||
--exclude /work --exclude /store --exclude '/store-*' --exclude /target \
|
--exclude /work --exclude /store --exclude '/store-*' --exclude /target \
|
||||||
--exclude /dist --exclude /.dev-fs --exclude /.git --exclude /.scratch \
|
--exclude /dist --exclude /.dev-fs --exclude /.git --exclude /.scratch \
|
||||||
--exclude '*.png' --exclude '/content*' \
|
--exclude '*.png' --exclude '/content*' \
|
||||||
|
|||||||
@@ -103,11 +103,23 @@ reintentar() {
|
|||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
if ! $SSH_CMD "$SB_USER@$SB_HOST" 'df -h .' >/dev/null 2>&1; then
|
# ── LA COMPROBACIÓN INICIAL TAMBIÉN REINTENTA ──────────────────────────────────────────────────
|
||||||
echo "!! No hay SSH al Storage Box ($SB_HOST:$SB_PORT)."
|
# Era un `if` de un solo intento, y el 2026-08-07 tiró la corrida al relanzar el respaldo justo al
|
||||||
echo "!! Si acabás de crearlo, el DNS tarda unos minutos en propagar. Reintentá."
|
# llegar a casa: el wifi todavía no había levantado, el `ssh` falló una vez y el script se rindió con
|
||||||
exit 1
|
# «no hay SSH» — cuando medio minuto después conectaba perfecto. Es el peor momento para rendirse:
|
||||||
fi
|
# quien relanza un respaldo interrumpido acaba de cambiar de red, así que el hipo es LO ESPERABLE.
|
||||||
|
# Mismo criterio que el bucle de transferencia: insistir es barato, rendirse cuesta una noche.
|
||||||
|
intento=1
|
||||||
|
until $SSH_CMD "$SB_USER@$SB_HOST" 'df -h .' >/dev/null 2>&1; do
|
||||||
|
if [ "$intento" -ge 20 ]; then
|
||||||
|
echo "!! No hay SSH al Storage Box ($SB_HOST:$SB_PORT) tras 20 intentos."
|
||||||
|
echo "!! Si acabás de crearlo, el DNS tarda unos minutos en propagar."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo ".. sin SSH al box todavía (¿red recién levantada?). Intento $intento; reintento en 15s."
|
||||||
|
intento=$((intento + 1))
|
||||||
|
sleep 15
|
||||||
|
done
|
||||||
|
|
||||||
echo "==> destino: $SB_USER@$SB_HOST:$SB_PORT ${SECO:+(SECO)}"
|
echo "==> destino: $SB_USER@$SB_HOST:$SB_PORT ${SECO:+(SECO)}"
|
||||||
$SSH_CMD "$SB_USER@$SB_HOST" 'mkdir hammer hammer/store hammer/repo hammer/estado' >/dev/null 2>&1 || true
|
$SSH_CMD "$SB_USER@$SB_HOST" 'mkdir hammer hammer/store hammer/repo hammer/estado' >/dev/null 2>&1 || true
|
||||||
|
|||||||
Reference in New Issue
Block a user