Bash signal trap čte $? — po SIGTERM je 0 a rollback se přeskočí
import { Aside } from ‘@astrojs/starlight/components’;
Symptom
Sekce “Symptom”Fail-closed orchestrační skript (změna credentialu: ALTER v DB → výměna
configu → restart → verify) měl trap na ERR INT TERM EXIT a v handleru
větvení „rc≠0 → rollback”. Testy poruch (vstříknuté selhání příkazu)
procházely. Ale při SIGTERM/SIGINT uprostřed okna skript skončil
exit 0, bez rollbacku, bez cleanupu — pomocné soubory se secrety
zůstaly na disku a systém zůstal v půlce přepnutí. Flaky: projevilo se jen
někdy, podle toho, kam signál dopadl.
Root cause
Sekce “Root cause”trap 'rc=$?; if [[ $rc -ne 0 ]]; then rollback; cleanup; fi; exit $rc' ERR INT TERM EXITPři selhání příkazu (ERR) je $? nenulové — větev funguje. Ale při
signálu bash doručí trap až po dokončení právě běžícího příkazu a $?
nese status toho posledního dokončeného — typicky úspěšného — příkazu,
tedy 0. Handler vyhodnotí „úspěch”, rollback přeskočí a exit 0
zamaskuje, že běh byl zabit uprostřed kritického okna.
Druhá vrstva téže pasti: cesty něco || die (kde die volá exit 1)
nefirují ERR trap (selhání je „ošetřené”) — bez EXIT trapu skončí
selhání za point-of-no-return také bez rollbacku.
Fix
Sekce “Fix”Oddělené handlery — signál je VŽDY přerušení, bez ohledu na $?:
# INT/TERM: nikdy nečíst $? — vždy rollback, konvenční exit 143trap 'trap - ERR INT TERM EXIT rollback || true; cleanup || true exit 143' INT TERM
# ERR + EXIT: tady $? smysl má (kryje i `něco || die` cesty)trap 'rc=$?; trap - ERR INT TERM EXIT if [[ $rc -ne 0 ]]; then rollback || true; cleanup || true; fi exit $rc' ERR EXITRollback musí být idempotentní (guard flag), protože handler může proběhnout vícekrát (explicitní volání + trap).
Jak se tomu vyvarovat v jiných systémech
Sekce “Jak se tomu vyvarovat v jiných systémech”- Detection:
grep -n "trap 'rc=\$?" *.sh+ zkontrolovat, zda signály sdílejí handler s ERR/EXIT. Testovací scénář: poslat skriptu SIGTERM uprostřed kritické fáze a ověřit, že rollback proběhl a exit ≠ 0. - Anti-pattern: jeden trap string pro
ERR INT TERM EXITs větvením podle$?; absence EXIT trapu u skriptů scmd || dievzorem. - Lepší přístup: rehearsal s fault-injection musí obsahovat i signálový scénář (kill v každé fázi), ne jen selhání příkazů — právě signálová větev se jinak nikdy neotestuje.
Sister bugs / související
Sekce “Sister bugs / související”- Příbuzná past:
set -eje uvnitř funkce volané vif/||kontextu vypnuté — selhání uprostřed funkce pokračuje dál. IFS=$'\n\t'rozbije word-splitting víceslovných konfigurací (CMD="sudo -u postgres psql"je pak jedno slovo) — smyčky a wrappery potřebují lokálníIFS=' '.