2 months ago
I'm experiencing a persistent Redis connection issue in my NestJS application. The app starts successfully but immediately fails to connect to Redis with ECONNREFUSED errors, causing healthcheck failures.
Environment Details:
Project: lumen
Environment: Development
Region: EU West (europe-west4-drams3a)
Development Service ID: c94d8ea5-f995-4c07-9465-365371abde40
Redis Service ID: b35df8da-a1af-4e49-86db-313f9588b2b8
Latest Deployment ID: a4987cb5-241b-4d99-a2bb-c36afbab941c
Current Configuration:
REDIS_URL=redis://default:${{Redis.REDIS_PASSWORD}}@${{Redis.RAILWAY_PRIVATE_DOMAIN}}:6379
Problem:
NestJS app starts successfully and binds to port 8080
Immediately after startup, ioredis throws continuous AggregateError [ECONNREFUSED] errors
Redis service is healthy and running (1/1 replicas, no failures)
Error is ECONNREFUSED (TCP connection refused), not ENOTFOUND (DNS failure)
Healthcheck fails with: MaxRetriesPerRequestError: Reached the max retries per request limit (which is 20)
Critical observation: Logs show "[RedisService] Redis connected" immediately followed by ECONNREFUSED errors, suggesting a race condition
Attempted Fixes (all failed):
Corrected service name from redis-dev to Redis
Tried using ${{ Redis.REDIS_URL }}
Tried using ${{ Redis.REDIS_PUBLIC_URL }}
Tried hardcoded private domain with reference variables for password
Disabled healthcheck - connection still fails
Multiple redeployments
Pinned Solution
2 months ago
The clue could be here in this line:
[RedisService] Redis connectedimmediately followed by ECONNREFUSED
That means one Redis client is connecting successfully, but another Redis in the app is still using a different config, often the default localhost:6379.
I would check the actual host/port in the ECONNREFUSED stack trace. Network Flow Logs in your deployment could be useful there.
If it says 127.0.0.1:6379 or ::1:6379, the failing client is not using your Railway Redis URL.
Then, because this is ioredis on Railway private networking, add dual-stack lookup support:
const redis = new Redis(${process.env.REDIS_URL}?family=0);
So, for your debugging I’d use is:
- Print the resolved REDIS_URL at startup (maybe also mask the password just in case).
- Check whether the ECONNREFUSED target is localhost, ::1, or the Railway private internal host.
- Make sure every Redis-using module gets the same parsed config.
Hope you find something.
8 Replies
Status changed to Open Railway • about 2 months ago
2 months ago
The clue could be here in this line:
[RedisService] Redis connectedimmediately followed by ECONNREFUSED
That means one Redis client is connecting successfully, but another Redis in the app is still using a different config, often the default localhost:6379.
I would check the actual host/port in the ECONNREFUSED stack trace. Network Flow Logs in your deployment could be useful there.
If it says 127.0.0.1:6379 or ::1:6379, the failing client is not using your Railway Redis URL.
Then, because this is ioredis on Railway private networking, add dual-stack lookup support:
const redis = new Redis(${process.env.REDIS_URL}?family=0);
So, for your debugging I’d use is:
- Print the resolved REDIS_URL at startup (maybe also mask the password just in case).
- Check whether the ECONNREFUSED target is localhost, ::1, or the Railway private internal host.
- Make sure every Redis-using module gets the same parsed config.
Hope you find something.
2 months ago
Also, I would recommend you to from manually building this line in other services in their environments:
REDIS_URL=redis://default:${{Redis.REDIS_PASSWORD}}@${{Redis.RAILWAY_PRIVATE_DOMAIN}}:6379
to use just this:
REDIS_URL=${{ Redis.REDIS_URL }}
because its just the same (and private networking still) and you wont do typo or something.
ve-jo
Also, I would recommend you to from manually building this line in other services in their environments: `REDIS_URL=redis://default:${{Redis.REDIS_PASSWORD}}@${{Redis.RAILWAY_PRIVATE_DOMAIN}}:6379` to use just this: `REDIS_URL=${{ Redis.REDIS_URL }}` because its just the same (and private networking still) and you wont do typo or something.
2 months ago
Tried both, didnt help
ve-jo
The clue could be here in this line: > `[RedisService] Redis connected` immediately followed by ECONNREFUSED That means one Redis client is connecting successfully, but another Redis in the app is still using a different config, often the default `localhost:6379`. I would check the actual host/port in the ECONNREFUSED stack trace. Network Flow Logs in your deployment could be useful there. If it says `127.0.0.1:6379` or `::1:6379`, the failing client is not using your Railway Redis URL. Then, because this is ioredis on Railway private networking, add dual-stack lookup support: const redis = new Redis(`${process.env.REDIS_URL}?family=0`); So, for your debugging I’d use is: 1. Print the resolved REDIS_URL at startup (maybe also mask the password just in case). 2. Check whether the ECONNREFUSED target is localhost, ::1, or the Railway private internal host. 3. Make sure every Redis-using module gets the same parsed config. Hope you find something.
2 months ago
Ill check this one
0x5b62656e5d
I'd try redeploying your Redis instance.
2 months ago
Nah. Tried as well
kerebere
Nah. Tried as well
2 months ago
Share some logs if still doesn't work. What host/port Redis client actually tries to connect to.
ve-jo
The clue could be here in this line: > `[RedisService] Redis connected` immediately followed by ECONNREFUSED That means one Redis client is connecting successfully, but another Redis in the app is still using a different config, often the default `localhost:6379`. I would check the actual host/port in the ECONNREFUSED stack trace. Network Flow Logs in your deployment could be useful there. If it says `127.0.0.1:6379` or `::1:6379`, the failing client is not using your Railway Redis URL. Then, because this is ioredis on Railway private networking, add dual-stack lookup support: const redis = new Redis(`${process.env.REDIS_URL}?family=0`); So, for your debugging I’d use is: 1. Print the resolved REDIS_URL at startup (maybe also mask the password just in case). 2. Check whether the ECONNREFUSED target is localhost, ::1, or the Railway private internal host. 3. Make sure every Redis-using module gets the same parsed config. Hope you find something.
a month ago
Thanks, this one helped me
Status changed to Solved brody • about 2 months ago