W3 bms-1 Rollback Playbook — 2026-07-10

Stan aktualny po incydencie 2026-07-09 (postmortem: docs/incidents/2026-07-09-w3-cascading-outage-postmortem.md) v32-prod działa od: 2026-07-09T22:49:21Z Wszystkie 7 bugów incydentu naprawione i zmergowane do main. Update 2026-07-11: oba wcześniej otwarte ryzyka (poniżej) zamknięte — generyczny push V32_* (PR 3667) i finalna rotacja w3_app (PR 3694, propagowana też na reso/socket).

Co teraz działa i dlaczego

ElementMechanizm
Backend W3v32-prod (ECR), env z backend-environment.env via secrets-sync
S3 W3s3-v32-prod (ECR), env z s3-environment.env via secrets-sync
Redis W3redis-v32 — redis:7-alpine, statyczny (brak CI/CD)
MongoDB W3V32_MONGODB_URL = V32_PMONGODB_URL = V32_DB_URI = V32_PINBOX_PROD_DB — zsynchronizowane w SOPS (PR #3612, ponownie wyrównane przy rotacji #3693)
Redis clientpersistent-patches/crudService.js — node-redis v5 API fix (PR #3607)
Twilio/OneSignalpersistent-patches/twilioService.js + pushNotification.helper.js — guard przed crash-loop (PR #3613)
Mongoosepersistent-patches/mongoose.js — connect-retry loop (PR #3613)
nginx-proxyVIRTUAL_HOST bez BOM — czyste env od secrets-sync
secrets-sync.yml key coverageGeneryczny push WSZYSTKICH kluczy V32_* (prefix-stripped), nie wąska lista — PR 3667
v32-prod-reso / v32-prod-socketOsobne compose (/home/p24-server-scripts/v3/v3reso/, .../v3socket/), NIE force-recreate’owane przez secrets-sync, ale ich env pliki są teraz utrzymywane aktualne przy każdym pushu (PR #3694) — patrz §Containers NOT covered w bms1-dr-plan.md

Obraz ECR (aktualny working)

ParametrWartość
ECR image563740926945.dkr.ecr.eu-central-1.amazonaws.com/v32-prod:latest
Image digestsha256:c63d663262e190776619ad370439ac31eea0a8a09e60bf80f2366af51d8e0b8eb
Image ID (short)976d1ac2f4ed
Git tagw3-working-2026-07-10
bms-1 IP94.23.26.113
BUILD dir/home/gitlab-runner/builds/eZQeLfuJe/0/pinbox24/p24-v-3.2/
Env file/opt/p24-infra/bms-1/pinbox24-w3.env

Scenariusz A — GitLab CI wytarł env files (główne ryzyko)

Trigger: CI job prod-back-end-deploy uruchamia git clean, który usuwa backend-environment.env i s3-environment.env (są untracked).

Symptomy:

  • PM2 crash-loop co 1-2s
  • api.w3.pinbox24.com zwraca 502/503
  • Logi: MongooseError buffering timed out lub username is required

Rollback (2 minuty):

gh workflow run secrets-sync.yml --repo radieu/p24-infra -f target=pinbox24-w3

Secrets-sync: re-deployuje env pliki, persistent-patches, force-recreate v32-prod + s3-v32-prod, oraz od PR #3694 również synchronizuje env v32-prod-reso/v32-prod-socket (bez ich restartu).

Scenariusz B — Nowy obraz ma bug (crash-loop po GitLab deploy)

Pinowanie do działającego digestu:

# SSH na bms-1 (94.23.26.113)
GOOD_IMAGE="563740926945.dkr.ecr.eu-central-1.amazonaws.com/v32-prod@sha256:c63d663262e190776619ad370439ac31eea0a8a09e60bf80f2366af51d8e0b8eb"
cd /home/gitlab-runner/builds/eZQeLfuJe/0/pinbox24/p24-v-3.2
 
# Podmień image w docker-compose i uruchom
sed -i "s|image:.*v32-prod.*|image: ${GOOD_IMAGE}|" docker-compose.yml
docker-compose up -d --force-recreate backend s3

Po weryfikacji — trigger secrets-sync żeby przywrócić oryginalny docker-compose z git:

gh workflow run secrets-sync.yml --repo radieu/p24-infra -f target=pinbox24-w3

Scenariusz C — V32_PMONGODB_URL rozjeżdża się z V32_MONGODB_URL

Symptom: logowanie działa (mongojs), ale /api/i18n/langs, formularze, widgety dashboardu zwracają 422 z buffering timed out after 10000ms.

Diagnoza:

docker exec v32-prod printenv MONGODB_URL | cut -c1-30
docker exec v32-prod printenv PMONGODB_URL | cut -c1-30
# Powinny mieć ten sam prefix (ten sam host/user/db)

Fix: zsynchronizować oba klucze w SOPS — V32_PMONGODB_URL = V32_MONGODB_URL — przez /request-sm lub sesję secret-manager. Następnie trigger secrets-sync.

Od PR secrets-sync.yml zawiera też defense-in-depth: jeśli te dwa klucze rozjadą się w SOPS, sync sam wymusza PMONGODB_URL = MONGODB_URL przy deployu.

Weryfikacja po rollbacku

# 1. Kontenery running
docker inspect v32-prod --format '{{.State.Status}}'        # running
docker inspect s3-v32-prod --format '{{.State.Status}}'     # running
docker inspect redis-v32 --format '{{.State.Status}}'       # running
 
# 2. PM2 workers (min. 1)
docker exec v32-prod pm2 jlist | python3 -c \
    "import json,sys; p=json.load(sys.stdin); print(sum(1 for x in p if x.get('pm2_env',{}).get('status')=='online'))"
 
# 3. MongoDB (oba klienty)
docker exec v32-prod sh -c "curl -s http://localhost:3000/api/i18n/langs | head -c 50"
# Oczekiwane: JSON (nie błąd mongoose)
 
# 4. nginx-proxy widzi kontener
docker exec nginx-proxy curl -s http://v32-prod:3000/api/i18n/langs | head -c 30
 
# 5. HTTP public
curl -s -o /dev/null -w "%{http_code}" https://api.w3.pinbox24.com/api/i18n/langs
# Oczekiwane: 200
 
# 6. reso/socket (osobne compose, ale env powinien być aktualny)
docker exec v32-prod-reso printenv MONGODB_URL | grep -oP '://[^:]+:\K[^@]+' | sha256sum | cut -c1-12
docker exec v32-prod printenv MONGODB_URL | grep -oP '://[^:]+:\K[^@]+' | sha256sum | cut -c1-12
# Oczekiwane: te same hashe

Krytyczne ryzyka (otwarte follow-upy po incydencie)

RyzykoStatusObejście
GitLab CI czyści env files na każdym deployOTWARTE — brak auto-retrigger secrets-sync po CIRęcznie: target=pinbox24-w3 po każdym CI deploy
secrets-sync ma wąskie listy kluczyZAMKNIĘTE — PR 3667: generyczny push wszystkich V32_*—
w3_app MongoDB password rotationZAMKNIĘTE — PR 3694, propagowane na main+reso+socket, wszystko zweryfikowane—
v32-prod-reso/v32-prod-socket poza force-recreate secrets-syncŚWIADOMA DECYZJA (nie ryzyko) — socket.io ma żywe połączenia, env i tak trzymany aktualny (PR #3694)Ręczny recreate gdy naprawdę potrzebny

Śledzenie

Issues: #3171 (orchestrator), #3609, #3611, #3612, #3613, #3614, #3660 (naprawione/zamknięte incydenty) Postmortem: docs/incidents/2026-07-09-w3-cascading-outage-postmortem.md DR plan: docs/playbooks/bms1-dr-plan.md