ai-coding-mines목차GitHub

락 파일의 `trap`을 빼먹으면 이후 전 회차가 죽는다

Git · 자동화

증상

락을 도입한 뒤로 작업이 아예 안 돈다. 로그도 안 남고 종료코드 0.

원인

정상 종료 경로에만 rm -f를 뒀다. 프로세스가 죽으면 락이 영구히 남고 이후 모든 회차가 조용히 exit한다.

해법

trap 'rm -f "$LOCK"' EXIT INT TERM HUP

★ 이건 앞 항목의 해법이 만든 다음 함정이다. pgrep 가드 → PID 락 도입 → 락 잔재. 하루에 두 단계로 겪었다.

★★★ 그리고 trap으로도 안 되는 경우가 있다 — 세 번째 단계

동시 실행을 확실히 막으려고 작업에 timeout을 걸었다. timeoutSIGKILL까지 갈 수 있고, SIGKILLtrap을 실행하지 않는다. fork 실패로 죽는 경우도 같다.

겹침을 막으려고 넣은 장치가 락 해제를 못 하게 만들었다. 2번의 해법을 3번이 무력화한 것이다.

장치막으려던 것만든 다음 함정
1pgrep 가드중복 실행자기 자신을 잡음
2PID 락 + trap1번 해결죽으면 락 잔재
3timeout 강제 종료겹침SIGKILLtrap을 건너뛰어 또 락 잔재

★★★ 방어를 하나 걸 때마다 새 실패 지점이 하나 생기고, 그게 앞 방어의 전제를 깨기도 한다.

해법 — 겹을 늘리되 서로 다른 가정 위에 둔다

# 1겹: 정리 코드를 실행할 기회가 있을 때
trap 'rm -f "$LOCK"' EXIT INT TERM HUP

# 2겹: 그 기회가 없었을 때 (SIGKILL·전원 차단·fork 실패)
[ -f "$LOCK" ] && [ $(( $(date +%s) - $(stat -c %Y "$LOCK") )) -gt 600 ] && rm -f "$LOCK"

★★ 단일 방어는 그 방어가 안 도는 경로에서 무너진다. trap은 "정리할 기회가 있다"를 전제하고, TTL은 그 전제가 깨진 경로를 덮는다.

TTL은 작업 timeout보다 넉넉해야 한다. 짧으면 정상 실행 중인 작업을 죽은 것으로 보고 동시 실행 방지가 통째로 무의미해진다.