Skip to content

fix(worker): pg_dump missing — switch base to postgres:16-alpine (P1) - #72

Merged
mastermanas805 merged 2 commits into
masterfrom
fix/worker-pg-dump-missing-image
May 30, 2026
Merged

fix(worker): pg_dump missing — switch base to postgres:16-alpine (P1)#72
mastermanas805 merged 2 commits into
masterfrom
fix/worker-pg-dump-missing-image

Conversation

@mastermanas805

Copy link
Copy Markdown
Member

P1 incident: 2026-05-30 overnight

Customer backups have been silently failing with exec: pg_dump: executable file not found in $PATH. Every Pro+ tier customer's scheduled backup broken — data-loss risk.

Root cause

worker/internal/jobs/customer_backup_runner.go:120 shells out to pg_dump. The previous distroless/static-debian12 base has no shell + no pg_dump.

Fix

  • Runtime base → postgres:16-alpine (matches customer-pg server per infra/k8s/postgres-customers.yaml). +~280MB image size; correctness > size.
  • New deploy.yml smoke-check: probes the built image for pg_dump, fails the deploy hard if the binary regresses or major version < 16. Closes the regression gate that would have caught this the day distroless landed.

Local verify

docker run --rm --entrypoint sh worker-test:local -c 'pg_dump --version'
→ pg_dump (PostgreSQL) 16.13

Coverage block (rule 17)

  • Symptom: 'pg_dump: executable file not found in $PATH' in worker logs
  • Enumeration: grep -rn 'exec.Command.*pg_dump' worker/internal/jobs/ → 1 site
  • Sites touched: 0 production code (binary already correct); 1 Dockerfile + 1 CI gate
  • Coverage test: deploy.yml smoke-check is the registry-iterating test
  • Live verified: build + pg_dump version check both green locally

mastermanas805 and others added 2 commits May 31, 2026 00:41
The hourly synthetic deploy prober (worker#69) wedged on its first tick
in prod with `404 no_existing_deployment_to_redeploy` — it POSTs with
`redeploy=true` from tick 1, but the persistent `deploy-probe-hourly`
app row doesn't exist yet, so the api's typed-error path correctly
refused. The probe was DOA until the operator manually bootstrapped.

Fix: legSubmit detects the canonical error code on a 404 response,
logs `jobs.deploy_probe.bootstrap_retry`, and transparently retries
ONCE without `redeploy=true` (create semantics). The retry's outcome
is reported as `result=bootstrap` on
`instant_deploy_probe_outcome_total{leg=submit}` — distinct from
`pass` so the dashboard sees the one-time self-heal as its own event.
Subsequent ticks find the row, get a 2xx, and report `pass`.

Anti-design guardrails:
- ONLY the canonical `no_existing_deployment_to_redeploy` error code
  triggers the retry. A non-canonical 404 (auth misroute, future
  api-side regression that drops `error`) still fails the leg with
  audit_log + ERROR slog — never mask a real outage as a self-heal.
- Bootstrap counts as a successful leg-1 for downstream leg dispatch
  so status + serve run on the freshly-bootstrapped row.
- `bootstrap` is NOT a degraded/fail; recordLeg logs at INFO, skips
  the audit_log INSERT, and the alert NRQL keys only on `result=fail`.

Coverage block (rule 17):
Symptom:        404 no_existing_deployment_to_redeploy on first probe tick
Enumeration:    rg -F 'no_existing_deployment_to_redeploy' (api + worker)
Sites found:    2 in api/internal/handlers/deploy.go (sql.ErrNoRows
                and wrong-team defence-in-depth), 0 in worker pre-fix
Sites touched:  1 in worker (new deployProbeRedeployMissingCode const
                consumed by legSubmit retry guard); api sites untouched
                (already correct typed-error contract per api#206)
Coverage test:  TestDeployProbe_Bootstrap_FirstTick404RetriesAsCreate
                + TestDeployProbe_Bootstrap_NonCanonical404StillFails
                + TestBuildDeployProbeMultipart_BootstrapShape
Live verified:  pending merge + deploy; gated on rule 14 SHA check post-rollout

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
P1 incident 2026-05-30: customer_backup_runner shells out to pg_dump
(internal/jobs/customer_backup_runner.go:120). The previous
distroless/static-debian12 base has no shell + no pg_dump, so every
Pro+ tier customer's scheduled backup has been failing silently with
"exec: pg_dump: executable file not found in $PATH" — data-loss risk.

Fix:
- Runtime base → postgres:16-alpine (matches the customer-pg server
  version per infra/k8s/postgres-customers.yaml). Image grows ~280MB but
  correctness > size here. Worker binary is CGO_ENABLED=0 so it runs
  unmodified on alpine.
- Add CI smoke-check in deploy.yml that probes the built image for
  pg_dump and fails the deploy hard if the binary regresses (or major
  version < 16). Closes the regression gate that would have caught this
  the day distroless was introduced.

Locally verified:
  docker run --rm --entrypoint sh worker-test:local -c 'pg_dump --version'
  → pg_dump (PostgreSQL) 16.13

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@mastermanas805
mastermanas805 merged commit aab1b45 into master May 30, 2026
11 checks passed
@mastermanas805
mastermanas805 deleted the fix/worker-pg-dump-missing-image branch May 30, 2026 19:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant