fix(scripts): complete teardowns and truthful update aborts (NEH-214, NEH-215) - #287
Merged
Merged
Conversation
… NEH-215) The 2026-08-03 Rionegro outage: update.sh's pre-stop `up -d db` recreated the db container under the live stack, network removal wedged on an orphaned container from a service dropped between releases (dtk-docs-1), and the abort path then printed "nothing changed" while the database sat stopped and detached. Compose exits 0 on that partial teardown, so set -e never fires. - add --remove-orphans to every compose down (update, stop, rollback, setup, restore path) and to start.sh's boot-time up - update.sh step 5 no longer mutates the running stack: probe first, and only `up -d --no-recreate db` when db is not already running - update.sh step 6 tears down explicitly after `systemctl stop dtk` (ExecStop only runs for an active unit) and asserts nothing from the compose project survives before proceeding; same assertion after the post-migration down - new STACK_TOUCHED tracking: the "nothing changed" abort message now prints only when container state was genuinely untouched; otherwise the abort reports service/container/port state and a recovery command - generate-secrets.sh rotation path gets the same gating (no recreate, no stopping a db it did not start) - check-stack-health.sh also requires the db's published port to be listening on the host (ss), catching the healthy-but-detached state
There was a problem hiding this comment.
Pull request overview
Improves update and teardown reliability following the Rionegro production incident.
Changes:
- Removes orphaned containers during lifecycle operations.
- Verifies update teardowns and reports actual abort state.
- Adds safer database startup gating and host-port health checks.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
scripts/update.sh |
Adds teardown assertions and state-aware recovery reporting. |
scripts/stop.sh |
Removes orphaned containers during shutdown. |
scripts/start.sh |
Removes orphans during startup reconciliation. |
scripts/setup.sh |
Cleans up orphans during setup teardown paths. |
scripts/rollback-update.sh |
Cleans up orphans during rollback operations. |
scripts/generate-secrets.sh |
Avoids unnecessary database recreation and shutdown. |
scripts/check-stack-health.sh |
Checks for a host-side database listener. |
Comment on lines
+154
to
+159
| DB_WAS_RUNNING=0 | ||
| if [ -n "$($COMPOSE ps --services --status running 2>/dev/null | grep -x db || true)" ]; then | ||
| DB_WAS_RUNNING=1 | ||
| else | ||
| $COMPOSE up -d --no-recreate db >/dev/null | ||
| fi |
Comment on lines
+364
to
+365
| STACK_TOUCHED=1 | ||
| $COMPOSE up -d --no-recreate db |
…-clear text generate-secrets.sh: a compose ps failure no longer reads as "db not running" (which could have stopped a db the script did not start); the oneshot now fails loudly instead, blocking dtk.service as designed. update.sh: the db-timeout and empty-dump aborts no longer claim the appliance was not touched — the EXIT trap now owns that call and reports the actual state.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.
Suppressed comments (3)
scripts/update.sh:193
- If
docker pscannot query the daemon,|| trueconverts that failure into an empty container list. If the subsequent network inspection also returns nonzero, this function reports success even though it verified nothing, defeating the fail-loud teardown assertion. Treat an inspection failure as an incomplete teardown.
leftovers="$(docker ps -aq --filter "label=com.docker.compose.project=$project" 2>/dev/null || true)"
scripts/generate-secrets.sh:166
- When this branch starts the database, a later
ALTER USERfailure exits immediately because ofset -e, before the conditional stop at lines 183–185. The script therefore leaves a previously stopped database running; handle the ALTER failure explicitly and stop only the container started here before exiting.
$COMPOSE up -d --no-recreate db >/dev/null
scripts/check-stack-health.sh:102
- When
ssis unavailable,db_port_listeningintentionally returns success without checking the port, but this message still claims the host listener was verified. Report that the port check was skipped so startup diagnostics remain truthful.
echo "✓ Stack healthy: db healthy and listening on the host, frontend running${NGINX_NOTE}."
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes the two urgent bugs from the 2026-08-03 Rionegro production incident.
What happened
update.sh's pre-stopup -d dbrecreated the db container under the live stack; network removal wedged on an orphaned container from a service dropped between releases (dtk-docs-1); the db was left stopped and detached from its published port while the abort path printed "nothing changed". Compose exits 0 on that partial teardown (reproduced locally), soset -enever fires — the failure is invisible to the script and to the operator.Changes
--remove-orphanson everycompose down(update.sh,stop.sh,rollback-update.sh,setup.sh, the restore path) and onstart.sh's boot-timeup, so containers from services dropped between releases can never hold the project network hostage.update.shstep 5 no longer mutates the running stack: it probes container state first and only runsup -d --no-recreate dbwhen db is not already running. The full recreate happens post-stop, from a clean slate.update.shstep 6 tears down explicitly aftersystemctl stop dtk— systemd only runsExecStopfor an active unit — and a newassert_stack_goneverifies no project containers or the network survive, aborting loudly if they do (this is what catches the exit-0 partial teardown). Same assertion after the post-migration down.STACK_TOUCHEDtracking: "nothing changed" now prints only when container state is genuinely untouched. Otherwise the abort reports the service state, per-container states, whether 127.0.0.1:5432 is listening on the host, and the recovery command.generate-secrets.sh's rotation path gets the same gating (no recreate from the boot-time oneshot; never stops a db it did not start).check-stack-health.shnow also requires the db's published port to be listening on the host (ss, no connection made; skipped ifssis absent) — the incident's exact signature was a container reporting healthy while nothing listened on the host.Validation
bash -nclean on all seven scripts.down, network removal fails "Resource is still in use", exit code 0);down --remove-orphansclears container and network; the project-name derivation used byassert_stack_goneworks on compose v5.3.0.backend) are NOT treated as orphans — verified a running profile-gated container survivesdown --remove-orphans, so this cannot destroy a developer's backend container.Linear: NEH-214, NEH-215 (GitHub mirrors #283, #284).