fix: bind-mount config/ as a directory, not a single file
CI / web (push) Successful in 17s
CI / api (push) Successful in 23s

Single-file bind mounts pin the container to that file's inode at
mount time. sed -i and most editors write-then-rename (atomic write),
which swaps in a new inode at the same path -- the container kept
reading the orphaned original and never saw edits, silently breaking
the hot-reload from the previous commit. Caught by actually testing
the reload live instead of trusting the code. Directory mounts
resolve paths dynamically and don't have this problem.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-12 22:06:52 -06:00
parent 1e1fb98afb
commit 5143840d90
2 changed files with 20 additions and 1 deletions
+13
View File
@@ -16,3 +16,16 @@ cycle (checks the file's mtime, reloads if changed) — no container restart nee
If the file fails to parse (bad YAML), the error is logged and the **previous**
in-memory config keeps running rather than crashing the poller.
## Gotcha that broke this on first deploy
`docker-compose.yml` originally bind-mounted the single file
(`./config/hosts.yaml:/app/config/hosts.yaml:ro`). Single-file bind mounts pin the
container to that file's **inode** at mount time. `sed -i`, most text editors, and any
tool that does an atomic write (write to a temp file, then `rename()` over the
original — the common safe-write pattern) swap in a *new* inode at the same path. The
container kept reading the original (now-orphaned) inode and never saw edits made this
way, no matter how long you waited for the next poll cycle. Fixed by mounting the
**directory** instead (`./config:/app/config:ro`), which resolves paths dynamically
rather than pinning to a specific inode. Confirmed via `docker exec ... stat` showing a
stale mtime that didn't match the host file before this fix.