E12 · Interrumpir y retomar
10 minClona el jornada-agentes y ejecuta las partes 1 y 2 del ensayo.
Listo cuando: aparecen rodando: 03.md · feito: 01.md 02.md y después execuções: 5 para 4 tarefas.
Clase 6 · 20 min
Una cola en carpetas sobrevive a una caída: lo que estaba corriendo vuelve a la entrada. Pero la misma reanudación que salva una copia atropella a la otra cuando dos corren en la misma carpeta. En esta clase interrumpes y reanudas una cola, provocas la colisión con números, bloqueas con flock y ves a la guardia de colisión preguntar antes de editar.
Empezar la clase
Objetivo: interrumpir y reanudar una cola, provocar la colisión de dos colas en la misma carpeta y bloquear con flock y con la guardia de colisión.
La cola casera de jornada-agentes, en carpetas. Haz clic en cada estado.
La cola durable de verdad, con base de datos, reintentos y compuertas, es el inemaccbot del curso de Colas. Aquí va la idea mínima, para ver la falla.
Ejecuta, mata el proceso a la mitad y ejecuta de nuevo. Una tarea falla en la primera ejecución.
Simulación ilustrativa en el navegador. El ensayo de verdad, con el script y un claude falso, está justo debajo.
Un claude FALSO en el PATH anota cada ejecución en un log. Contar las líneas del log muestra cuántas veces corrió cada tarea.
cd ~/jornada-agentes # git clone https://github.com/inematds/jornada-agentes.git ~/jornada-agentes
E=${TMPDIR:-/tmp}/ensaio-multi/fila; rm -rf $E && mkdir -p $E/bin
cat > $E/bin/claude <<'SH'
#!/usr/bin/env bash
# claude FALSO: anota quién ejecutó qué, tarda 1 s y responde (no se llama a ningún modelo)
echo "$PPID $2" >> "${E_LOG:?}"; sleep 1; echo "resposta para: $2"
SH
chmod +x $E/bin/claude; export PATH=$E/bin:$PATH E_LOG=$E/execucoes.log
nova_fila() { rm -rf $E/fila $E_LOG; mkdir -p $E/fila/entrada; for i in 1 2 3 4; do echo "tarefa $i" > $E/fila/entrada/0$i.md; done; }
F=./ferramentas/fila-caseira.sh
echo "## 1) roda e é interrompida no meio"
nova_fila; timeout -s INT 2.5 $F $E/fila
echo "rodando: $(ls $E/fila/rodando) · feito: $(ls $E/fila/feito | tr '\n' ' ')"
echo "## 2) roda de novo: retoma"
$F $E/fila | tail -1
echo "execuções: $(wc -l < $E_LOG) para 4 tarefas"
echo "## 3) duas filas na mesma pasta, ao mesmo tempo"
nova_fila; $F $E/fila > $E/a.log 2>&1 & $F $E/fila > $E/b.log 2>&1 & wait
echo "execuções: $(wc -l < $E_LOG) para 4 tarefas · repetidas: $(cut -d' ' -f2- $E_LOG | sort | uniq -d | tr '\n' ' ')"
echo "## 4) a mesma coisa com flock"
nova_fila; flock -n $E/fila.lock $F $E/fila > $E/a.log 2>&1 &
sleep 0.3; flock -n $E/fila.lock $F $E/fila || echo "outra fila já roda nesta pasta (saída $?)"; wait
echo "execuções: $(wc -l < $E_LOG) para 4 tarefas"## 1) roda e é interrompida no meio → 01.md feito → 02.md feito → 03.md rodando: 03.md · feito: 01.md 02.md ## 2) roda de novo: retoma entrada: 0 · feito: 4 · falhou: 0 execuções: 5 para 4 tarefas ## 3) duas filas na mesma pasta, ao mesmo tempo execuções: 8 para 4 tarefas · repetidas: tarefa 1 tarefa 2 tarefa 3 tarefa 4 ## 4) a mesma coisa com flock outra fila já roda nesta pasta (saída 1) execuções: 4 para 4 tarefas
Ejecutado tres veces, mismo resultado. En 2, la tarea 3 corrió dos veces (interrumpida y retomada): la tarea tiene que aguantar correr de nuevo. En 3, las cuatro corrieron dos veces. En 4, la segunda copia ni siquiera empezó.
El log de una de las dos copias de la ronda 3 (ruta acortada a $E):
→ 01.md rm: cannot remove '$E/fila/fila/rodando/01.md': No such file or directory feito mv: cannot stat '$E/fila/fila/entrada/02.md': No such file or directory → 02.md (…)
El mv falla porque la otra copia ya tomó el archivo, pero el script sigue y ejecuta la tarea de todos modos, con el archivo que la otra movió a rodando/. Y la retomada de una copia devuelve a la entrada lo que la otra está ejecutando. No es un defecto de un agente: el script fue hecho para una sola copia, y el candado es lo que lo garantiza.
El proyecto de práctica trae colisao.mjs, un hook que anota quién editó cada archivo y pregunta antes de que otra sesión edite. Aquí, solo la detección; el hook como guardia es el curso 4.
cd ~/treino-multi
export INEMA_RUNTIME_ESTADO=${TMPDIR:-/tmp}/ensaio-multi/colisao; rm -rf $INEMA_RUNTIME_ESTADO
G=runtime/mods/runtime-guarda/hooks/colisao.mjs
j() { printf '{"session_id":"%s","cwd":"%s","tool_input":{"file_path":"notas.md"}}' "$1" "$PWD"; }
echo "rascunho" > notas.md
j sessao-AAAAAAAA | node $G pos # a sessão A acabou de editar notas.md
echo "## A quer editar de novo"; j sessao-AAAAAAAA | node $G pre; echo "(saída $?)"
echo "## B quer editar o mesmo arquivo"; j sessao-BBBBBBBB | node $G pre; echo; echo "(saída $?)"## A quer editar de novo
(saída 0)
## B quer editar o mesmo arquivo
{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"ask","permissionDecisionReason":"Guarda de colisão: Outra sessão (sessao-A) editou notas.md agora há pouco. Seguir mesmo assim, usar outra cópia (worktree) ou cancelar?"}}
(saída 0)La misma sesión pasa callada. La otra recibe "permissionDecision":"ask": Claude Code se detiene y pregunta. La ventana predeterminada es de 30 min (INEMA_COLISAO_MIN). INEMA_RUNTIME_ESTADO manda el registro a la carpeta de ensayo, para no mezclarlo con el tuyo real.
Del LESSONS.md del proyecto de monitoreo de INEMA, con fecha. Cada una se convirtió en una regla de una línea.
Cursos hechos en paralelo por subagentes compartían la misma carpeta temporal. Una carpeta de imágenes con nombre genérico colisionó: el script de un agente se saltó la imagen porque la arte del otro ya existía.
Regla: carpeta temporal con el id de la tarea en el nombre.
En un archivo compartido entre sesiones (pendientes, límites), editar por el número de línea erró el objetivo: otra sesión había insertado algo arriba.
Regla: ubicar por el texto de la propia línea, nunca por el número.
Una imagen generada directo en la carpeta del repo fue commiteada por otra sesión que ejecutó git add -A. Y ediciones del portal fueron commiteadas por otra sesión antes de tiempo.
Regla: generar fuera del repo y preparar el cambio en un worktree aislado, aun con los archivos limpios.
Un servidor de prueba de otra sesión fue derribado porque ocupaba el puerto "de siempre".
Regla: puerto realmente libre y solo matar un proceso después de confirmar que su carpeta (/proc/[pid]/cwd) es la tuya.
Cola, colisión y guardia, sin gastar cuota.
Clona el jornada-agentes y ejecuta las partes 1 y 2 del ensayo.
Listo cuando: aparecen rodando: 03.md · feito: 01.md 02.md y después execuções: 5 para 4 tarefas.
Ejecuta las partes 3 y 4. Después escribe, en una línea de tu AGENTS.md o CLAUDE.md, la regla de bloqueo para los scripts de cola que usas.
Listo cuando: la parte 3 imprime execuções: 8 para 4 tarefas; la parte 4 imprime outra fila já roda nesta pasta (saída 1) y execuções: 4 para 4 tarefas; grep -c flock AGENTS.md CLAUDE.md encuentra tu regla.
Ejecuta el ensayo de la guardia en el proyecto de entrenamiento.
Listo cuando: la sesión A sale sin texto y (saída 0); la sesión B imprime "permissionDecision":"ask" con Outra sessão (sessao-A) editou notas.md.
Pregunta 1 de 4
La cola se cayó en medio de la tarea 3. Al retomar, ¿cuántas veces habrá corrido la tarea 3?competencia
Pregunta 2 de 4
Dos copias de la cola casera en la misma carpeta. ¿Qué mostró el ensayo?competencia
Pregunta 3 de 4
¿Cuál es la corrección mínima para la colisión de dos colas?
Pregunta 4 de 4
¿Qué responde la guardia de colisión cuando otra sesión editó el archivo hace poco?
Elige una alternativa. La explicación aparece después de tu intento.