a6976186d4
gates / consistency-and-conventions (push) Successful in 25s
- failure_telegram_listener_254.md: /capture->ffmpeg 254 exit chain,
CHLD-trap blind spot, bare 'wait'-under-set -e daemon kill, systemd
crash-loop + getUpdates offset reset, flock path divergence, fix
(set -e-safe reap + persisted offset, fcfa2a5)
- lesson_bash_errexit_wait.md: capturing a failing child's status with
'wait $pid; rc=$?' under set -euo pipefail aborts the parent;
always use 'wait $pid 2>/dev/null || rc=$?'
1.4 KiB
1.4 KiB
Lesson: set -e + wait "$pid"; rc=$? kills the shell on non-zero child exit
Symptom: a daemon loop crash-looping with status = a background child's exit code (set -euo pipefail shell).
Debugging approach that worked:
- Before theorizing, reproduce the failing command chain in isolation AND check the exact exit code of each link (ffmpeg on absent device returned 254 — not the "expected" 231 from /dev/null!).
- Bisect the propagation path: raw command → chain wrapper → bg child spawn → CHLD trap
reaping → reap_commands wait fallback. Using
bash -xon a byte-identical reduced script (trap_full.sh) pinpointed the death at+ wait <pid>. - Baseline shell semantics test:
bash -c 'set -e; false; echo REACHED'→ exits without REACHED. Proves;does NOT shield a failing simple command from errexit. Many devs wrongly assumecmd; rc=$?is always safe — it is NOT underset -e. - Bash
wait -nin a while-condition ALSO conceals non-zero child exits (loop body skipped) → a "reaping" trap silently loses the failure info → downstream fallbacks go to the dangerous path.
Key insight: with set -euo pipefail, ANY background failure can become a main-shell
death if reaped via wait "$pid" in a plain command list. The safe capture is
rc=0; wait "$pid" 2>/dev/null || rc=$? (errexit suppressed by ||), or run reaping
inside if wait ...; then ... else rc=$?; fi.