23 days 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
22 days 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 • 23 days ago
22 days 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.
22 days 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.
22 days 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.
22 days ago
Ill check this one
0x5b62656e5d
I'd try redeploying your Redis instance.
22 days ago
Nah. Tried as well
kerebere
Nah. Tried as well
22 days 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.
22 days ago
Thanks, this one helped me
Status changed to Solved brody • 22 days ago