Playbook: v32-prod-reso / -socket crash-loop after a redis-client (v5) cutover — stale image
Service: v32-prod-reso (w3.reso-integration-addrecords.pinbox24.com, RESO EUROPA — ~86% of W3
traffic) and v32-prod-socket, on bms-1 (94.23.26.113).
First seen: radieu/p24-infra#3923 (2026-07-12), the night of the #3712 local-redis-v32 cutover.
Trigger / symptoms
EndpointDown(blackbox) onhttps://w3.reso-integration-addrecords.pinbox24.com— fast, consistent HTTP 502 (nginx-proxyup, upstream dead). May pair with the same on the socket endpoint.docker exec v32-prod-reso pm2 list→backendonlinebutrestartclimbing (30→100+) withuptime 0s; the app never binds port 3000.- App logs are a red herring:
pm2 outspamsMongoose connecting,pm2 errspamsConnecting with redis in redisConfig on host redis-v32— with no explicit stack. MongoDB and Redis are actually reachable and their credentials are correct; do not chase them.
The actual root cause
The bind-mounted patch persistent-patches/crudService.js is written for the node-redis v5 API
(redis.createClient({ socket: { host, port } }) + redisClient.connect()). The crash is:
TypeError: helperService.redisClient.connect is not a function
at /app/app-backend/helperFunction/crudService.js:97
.connect() only exists in node-redis v4+. It appears when the container’s image ships an old
redis npm (e.g. 2.8.0). The main v32-prod runs the ECR image
(563740926945…/v32-prod, redis 5.12.1) so it works; if reso/socket are still on the old
private-registry.dev.pinbox24.com/v32-prod image (redis 2.8.0) they hard-crash on boot.
Underlying cause: the cutover updated docker-compose.yml’s reso/socket image: to the ECR v5
image, but the running containers were never recreated, so they kept the stale image. (An earlier
recreate had also dropped reso’s test-net attachment — see
v32-prod-prod-v-3-net-persistence.md.)
Diagnose (agents CAN SSH bms-1 from bms-4 post-VPN-decommission)
ssh -i ~/.ssh/vps_root_key root@94.23.26.113
# 1. Confirm the crash (not creds): run the app once in foreground
docker exec v32-prod-reso pm2 stop backend
docker exec v32-prod-reso sh -c 'cd /app && timeout 15 node app-backend/app.js 2>&1' | grep -i 'connect is not a function'
docker exec v32-prod-reso pm2 start backend
# 2. Compare redis npm version reso vs the healthy main backend
docker exec v32-prod-reso node -e 'console.log(require("redis/package.json").version)' # bad: 2.8.0
docker exec v32-prod node -e 'console.log(require("redis/package.json").version)' # good: 5.x
# 3. Confirm the compose file already declares the correct ECR image + both networks
D=/home/gitlab-runner/builds/eZQeLfuJe/0/pinbox24/p24-v-3.2
grep -nE 'container_name: v32-prod-(reso|socket)|image:|- (test-net|prod-v-3-net)' $D/docker-compose.yml
# ⚠️ NEVER run bare `docker-compose config` here — it prints all W3 prod creds (incident #3750).Fix — recreate reso/socket from the (corrected) compose file
If the compose reso/socket blocks already point at the ECR v5 image and list both
prod-v-3-net + test-net (they should after the cutover), just recreate:
# PLAYBOOK: v32-reso-socket-stale-image-redis-v5-crashloop.md
D=/home/gitlab-runner/builds/eZQeLfuJe/0/pinbox24/p24-v-3.2
ssh -i ~/.ssh/vps_root_key root@94.23.26.113 \
"cd $D && docker-compose up -d --no-deps --force-recreate reso socket"If the compose blocks are NOT yet corrected, edit only the image: line (→
563740926945.dkr.ecr.eu-central-1.amazonaws.com/v32-prod) and ensure networks: lists both
prod-v-3-net and test-net for each of reso and socket, then run the recreate above. Use
targeted sed/edit on those lines only — do not touch env_file blocks, never print the file.
The ECR v5 image is already present locally (
docker images | grep 976d1ac2f4ed), so no registry pull/auth is needed. It is the exact image the healthyv32-prodbackend runs.
Verify recovery
docker exec v32-prod-reso pm2 list | grep backend # online, restart 0, uptime climbing
docker exec v32-prod-reso node -e 'console.log(require("redis/package.json").version)' # 5.x
docker inspect v32-prod-reso -f '{{range $k,$v := .NetworkSettings.Networks}}{{$k}} {{end}}' # prod-v-3-net test-net
curl -s -o /dev/null -w '%{http_code}\n' https://w3.reso-integration-addrecords.pinbox24.com # 200Close the EndpointDown issue once the endpoint is a stable 200 and PM2 restart stays flat.
Prevention / systemic follow-up
- Any redis-client API bump in
persistent-patches/crudService.jsmust land together with an image whoseredisnpm ≥ 4 for every container that mounts it (v32-prod,reso,socket). A patch that runs on one tier’s image but not another’s silently strands the lagging tier. - The committed source-of-truth compose IS reconciled by p24-infra, not GitLab.
secrets-sync.yml(jobsync-pinbox24-w3)scpsinfra-src/pinbox24/w3/docker-compose.ymlto the deploy path/home/gitlab-runner/builds/eZQeLfuJe/0/pinbox24/p24-v-3.2/docker-compose.ymland thendocker-compose up -d --force-recreate ... reso socket. So any manual on-server compose edit is transient — the nextpinbox24-w3sync overwrites it and force-recreates from the repo. The reso/socket ECR-image +test-nettopology was persisted into the committed compose in #3933 (2026-07-12); an earlier redis-v5 fix that only touched the on-server file would be silently reverted on the next sync. Always land the compose fix ininfra-src/pinbox24/w3/docker-compose.yml.
Related
v32-prod-prod-v-3-net-persistence.md— reso/socket droppingtest-net/prod-v-3-neton recreate.v32-prod-mongoose-authfail-storm.md— the “looks like Mongoose/Redis creds but isn’t” sibling; rule creds out fast.pinbox24-bms1-redis-wrongpass.md— the genuine Redis WRONGPASS case (different signature: explicitWRONGPASS, not aTypeError).