sync_audio_bulk.sh: lote de sincronizacion de audio TTS con parada en primer fallo #215

Merged
rafa merged 3 commits from feat/issue-sync-bulk-script into main 2026-08-24 19:28:21 +00:00
Owner

Formaliza como script versionado el wrapper que usé a mano el 2026-08-24 para subir a producción los 186 audios TTS pendientes del cron de backlog local (ver hilo en Buzz). Pedido por Codix como corrección permanente tras encontrar un bug real en la version ad-hoc.

Qué hace

scripts/sync_audio_bulk.sh envuelve scripts/sync_audio_to_prod.py (que ya calcula y verifica SHA-256 en cada subida desde el #213) para sincronizar LOTES de posts:

  • Entrada explicita de IDs: --ids csv, --file ruta (uno por linea) o --carta post_id.
  • Carga los IDs en un array (mapfile/IFS read -a) ANTES de lanzar cualquier ssh -- nunca while read ... < fichero.
  • Redirige el stdin del proceso hijo a /dev/null en cada invocacion.
  • Para en el PRIMER fallo real, sin reintentos ciegos.
  • Resumen ok/skip al cierre.
  • --dry-run soportado (pasa el flag al script Python).

Por que hace falta

Un primer intento con un while read id; do ...; done < fichero normal parecia funcionar (rc=0, log "sin error") pero solo proceso 1 de 184 posts: sync_audio_to_prod.py llama a ssh internamente, que hereda el mismo stdin que el bucle estaba leyendo, se come el resto del fichero de IDs, y el bucle termina limpio tras la primera iteracion. Se detecto solo verificando el resultado real en produccion (el conteo de metas no cuadraba), no por ningun error visible. Documentado tambien en la memoria del proyecto (feedback-bash-while-read-ssh-stdin).

Probado

  • --dry-run con 3 IDs conocidos (con symlink a wordpress/wp-content/uploads/tts del checkout principal, mismo patron que el resto de worktrees): PLAN correcto, ok=3/3.
  • --dry-run --file con los 186 IDs reales del backfill: ok=186/186, sin tocar produccion.
  • Uso incorrecto (sin argumentos): sale con el mensaje de uso y exit 2.
  • El lote real de 186 posts (ejecutado a mano antes de este PR, con la logica equivalente) quedo verificado en produccion: fea_audio_done=fea_audio_sha256=969, 0 discrepancias, verificacion por conjunto de los 186 IDs sin ningun NULL.

No toca produccion por si mismo (solo añade el script + doc). Pido revision independiente antes de mergear.

Formaliza como script versionado el wrapper que usé a mano el 2026-08-24 para subir a producción los 186 audios TTS pendientes del cron de backlog local (ver hilo en Buzz). Pedido por Codix como corrección permanente tras encontrar un bug real en la version ad-hoc. ## Qué hace `scripts/sync_audio_bulk.sh` envuelve `scripts/sync_audio_to_prod.py` (que ya calcula y verifica SHA-256 en cada subida desde el #213) para sincronizar LOTES de posts: - Entrada explicita de IDs: `--ids csv`, `--file ruta` (uno por linea) o `--carta post_id`. - Carga los IDs en un array (`mapfile`/`IFS read -a`) ANTES de lanzar cualquier ssh -- nunca `while read ... < fichero`. - Redirige el stdin del proceso hijo a `/dev/null` en cada invocacion. - Para en el PRIMER fallo real, sin reintentos ciegos. - Resumen `ok/skip` al cierre. - `--dry-run` soportado (pasa el flag al script Python). ## Por que hace falta Un primer intento con un `while read id; do ...; done < fichero` normal parecia funcionar (`rc=0`, log "sin error") pero solo proceso 1 de 184 posts: `sync_audio_to_prod.py` llama a `ssh` internamente, que hereda el mismo stdin que el bucle estaba leyendo, se come el resto del fichero de IDs, y el bucle termina limpio tras la primera iteracion. Se detecto solo verificando el resultado real en produccion (el conteo de metas no cuadraba), no por ningun error visible. Documentado tambien en la memoria del proyecto (`feedback-bash-while-read-ssh-stdin`). ## Probado - `--dry-run` con 3 IDs conocidos (con symlink a `wordpress/wp-content/uploads/tts` del checkout principal, mismo patron que el resto de worktrees): PLAN correcto, ok=3/3. - `--dry-run --file` con los 186 IDs reales del backfill: ok=186/186, sin tocar produccion. - Uso incorrecto (sin argumentos): sale con el mensaje de uso y exit 2. - El lote real de 186 posts (ejecutado a mano antes de este PR, con la logica equivalente) quedo verificado en produccion: `fea_audio_done`=`fea_audio_sha256`=969, 0 discrepancias, verificacion por conjunto de los 186 IDs sin ningun NULL. No toca produccion por si mismo (solo añade el script + doc). Pido revision independiente antes de mergear.
rafa added 1 commit 2026-08-24 19:23:19 +00:00
Envoltorio de sync_audio_to_prod.py para lotes de posts: carga los IDs con
un array (mapfile/--ids/--file) antes de cualquier ssh y redirige el stdin
del proceso hijo a /dev/null, evitando el bug de un while-read compartiendo
stdin con ssh (ssh se come el resto del fichero de IDs y el bucle termina
sin error tras procesar solo el primero — visto en real el 2026-08-24,
lote de 184 que solo sincronizó 1). Para en el primer fallo real, sin
reintentos ciegos, y da un resumen ok/skip al cierre.

Documentado en README con ejemplo de uso y variables de entorno.
rafa added 1 commit 2026-08-24 19:26:12 +00:00
- carta_article_ids() en sync_audio_to_prod.py ahora comprueba returncode
  del docker exec y lanza RuntimeError si falla, en vez de devolver una
  lista vacía silenciosa (bug preexistente: un fallo de Docker/consulta se
  confundía con "la carta no tiene artículos").
- El wrapper resuelve --carta a fichero temporal en vez de mapfile con
  sustitución de procesos (mapfile < <(cmd) no deja comprobar el exit
  code real de cmd), captura el rc de python explícitamente y aborta con
  exit 1 sin sincronizar nada si la consulta falla.
- sys.path ya no depende del cwd ("scripts" relativo): se pasa la ruta
  absoluta de SCRIPT_DIR al script inline.

Probado: --carta real sin cambios de comportamiento (28 candidatos,
ok=21/skip=7); consulta rota a propósito (FEA_DB_CONTAINER inexistente)
aborta limpio con exit=1 y 0 sincronizaciones; invocación desde otro
directorio de trabajo da el mismo resultado que desde la raíz del repo.

Revisión de Codix en el PR #215.
rafa added 1 commit 2026-08-24 19:27:45 +00:00
Mismo patrón que carta_article_ids() (commit anterior): si el docker exec
contra el contenedor WP local fallaba (contenedor caído/inexistente),
local_meta() devolvía stdout vacío en vez de comprobar returncode.
sync_one() interpretaba la cadena vacía como "sin-audio-local" (skip), no
como error, así que un lote entero podía acabar "ok=0/skip=N" tras perder
Docker en vez de abortar.

Ahora lanza RuntimeError con el stderr si docker exec falla; se propaga
por sync_one() hasta el try/except de main(), que ya cuenta err y devuelve
1 — el wrapper aborta correctamente con exit=1 y 0 sincronizaciones.

Probado: FEA_WP_CONTAINER inexistente + --ids → aborta en el primer ID
(exit=1, ok=0). Camino normal (--ids con contenedor real, dry-run) sigue
dando el mismo resultado que antes.

Revisión de Codix en el PR #215.
rafa merged commit 1333a2bb64 into main 2026-08-24 19:28:21 +00:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: rafa/feadulta#215