E12 · Interrupt and resume
10 minClone jornada-agentes and run parts 1 and 2 of the rehearsal.
Done when: you see rodando: 03.md · feito: 01.md 02.md and then execuções: 5 para 4 tarefas.
Lesson 6 · 20 min
A queue in folders survives a crash: what was running goes back to the entrada. But the same resume that saves one copy tramples the other when two run in the same folder. In this lesson you interrupt and resume a queue, trigger the collision with numbers, lock with flock, and watch the collision guard ask before editing.
Start the lesson
Goal: interrupt and resume a queue, trigger the collision of two queues in the same folder, and lock with flock and with the collision guard.
The homemade queue from jornada-agentes, in folders. Click each state.
The truly durable queue, with a database, retries and gates, is the inemaccbot from the Queues course. Here is the minimal idea, so you can see the failure.
Run it, kill the process midway, and run it again. One task fails on the first run.
Illustrative simulation in the browser. The real rehearsal, with the script and a fake claude, is right below.
A FAKE claude on the PATH logs each run. Counting the log lines shows how many times each task ran.
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
# FAKE claude: logs who ran what, takes 1 s and answers (no model is called)
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
Run three times, same result. In 2, task 3 ran twice (interrupted and resumed): the task has to survive running again. In 3, all four ran twice. In 4, the second copy never even started.
The log of one of the two copies from run 3 (path shortened to $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 (…)
The mv fails because the other copy already took the file, but the script carries on and runs the task anyway, with the file the other copy moved to rodando/. And one copy's resume sends back to the input what the other is running. It is not a bug in an agent: the script was built for a single copy, and the lock is what guarantees that.
The training project ships colisao.mjs, a hook that logs who edited each file and asks before another session edits it. Here, only the detection; the hook as a guard is course 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 # session A just edited 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)The same session passes silently. The other one gets "permissionDecision":"ask": Claude Code stops and asks. The default window is 30 min (INEMA_COLISAO_MIN). INEMA_RUNTIME_ESTADO sends the log to the rehearsal folder, so it does not mix with your real one.
From LESSONS.md of the INEMA monitoring project, with dates. Each one became a one-line rule.
Courses built in parallel by subagents shared the same temporary folder. An image folder with a generic name collided: one agent's script skipped the image because the other's art already existed.
Rule: temporary folder with the task id in its name.
In a file shared between sessions (pending items, limits), editing by line number hit the wrong target: another session had inserted at the top.
Rule: match on the line's own text, never on the number.
An image generated straight into the repo folder was committed by another session that ran git add -A. And portal edits were committed by another session before their time.
Rule: generate outside the repo and prepare the change in an isolated worktree, even when the files are clean.
A test server from another session was killed because it was using the "usual" port.
Rule: pick a truly free port and only kill a process after checking that its folder (/proc/[pid]/cwd) is yours.
Queue, collision, and guard, without spending quota.
Clone jornada-agentes and run parts 1 and 2 of the rehearsal.
Done when: you see rodando: 03.md · feito: 01.md 02.md and then execuções: 5 para 4 tarefas.
Run parts 3 and 4. Then write, in one line of your AGENTS.md or CLAUDE.md, the lock rule for the queue scripts you use.
Done when: part 3 prints execuções: 8 para 4 tarefas; part 4 prints outra fila já roda nesta pasta (saída 1) and execuções: 4 para 4 tarefas; grep -c flock AGENTS.md CLAUDE.md finds your rule.
Run the guard rehearsal in the practice project.
Done when: session A exits with no text and (saída 0); session B prints "permissionDecision":"ask" with Outra sessão (sessao-A) editou notas.md.
Question 1 of 4
The queue crashed in the middle of task 3. When it resumes, how many times will task 3 have run?skill
Question 2 of 4
Two copies of the home-made queue in the same folder. What did the rehearsal show?skill
Question 3 of 4
What is the minimum fix for the collision of two queues?
Question 4 of 4
What does the collision guard answer when another session edited the file a moment ago?
Choose one option. The explanation appears after your attempt.