3 months ago
I'm getting this when I try to connect to redis from localhost: Error: connect ETIMEDOUT at TLSSocket.<anonymous> [rest is truncated for privacy]
Cursor provided the following review of my console logs:
The exceptions.log file shows an entry at Wed May 07 2025 14:51:42 GMT-0300, which corresponds to your latest run (17:51:42 UTC). This log entry also records the same connect ETIMEDOUT error.
The problem is still related to the inability to connect to [url removed] via TLS.
I am running NestJS with BullMQ and Bullboard.
I see this in the console:
```
> nest start
2025-05-07T17:51:31.495Z info: [NestFactory] Starting Nest application... +0ms
2025-05-07T17:51:31.519Z info: [InstanceLoader] PrismaModule dependencies initialized +24ms
2025-05-07T17:51:31.520Z info: [InstanceLoader] LoggingModule dependencies initialized +1ms
2025-05-07T17:51:31.520Z info: [InstanceLoader] BullBoardModule dependencies initialized +0ms
2025-05-07T17:51:31.532Z info: [InstanceLoader] ConfigHostModule dependencies initialized +12ms
2025-05-07T17:51:31.532Z info: [InstanceLoader] BullBoardFeatureModule dependencies initialized +0ms
2025-05-07T17:51:31.533Z info: [InstanceLoader] DiscoveryModule dependencies initialized +1ms
2025-05-07T17:51:31.533Z info: [InstanceLoader] BullBoardRootModule dependencies initialized +0ms
2025-05-07T17:51:31.533Z info: [InstanceLoader] ConfigModule dependencies initialized +0ms
2025-05-07T17:51:31.533Z info: [InstanceLoader] ConfigModule dependencies initialized +0ms
2025-05-07T17:51:31.534Z info: [AppModule] AppModule initialized. +0ms
2025-05-07T17:51:31.534Z info: [AppModule] DIAGNOSTIC - NODE_ENV: development +0ms
2025-05-07T17:51:31.534Z info: [AppModule] DIAGNOSTIC - BullMQ Redis family (derived from env): 0 +0ms
2025-05-07T17:51:31.534Z info: [AppModule] DIAGNOSTIC - REDIS_HOST: [redacted] +0ms
2025-05-07T17:51:31.534Z info: [AppModule] DIAGNOSTIC - REDIS_PORT: [redacted] +0ms
2025-05-07T17:51:31.534Z info: [AppModule] DIAGNOSTIC - REDIS_USERNAME: [redacted] +0ms
2025-05-07T17:51:31.534Z info: [AppModule] DIAGNOSTIC - REDIS_PASSWORD is set: true +0ms
2025-05-07T17:51:31.535Z info: [InstanceLoader] BullModule dependencies initialized +1ms
2025-05-07T17:51:31.536Z info: [AccountsController] FlowProducer initialized (Host: [redacted], Port: [redacted], Username: [redacted], Password Set: true, Family: 0) +1ms
2025-05-07T17:51:31.536Z info: [InstanceLoader] BullModule dependencies initialized +0ms
2025-05-07T17:51:31.540Z info: [RoutesResolver] AppController {/}: +3ms
2025-05-07T17:51:31.541Z info: [RouterExplorer] Mapped {/, GET} route +1ms
2025-05-07T17:51:31.594Z info: AccountImportProcessor initialized and attached to queue: account-import +52ms
2025-05-07T17:51:31.595Z info: [NestApplication] Nest application successfully started +1ms
2025-05-07T17:51:31.596Z info: [NestApplication] Application is running on: http://localhost:3001 +1ms
2025-05-07T17:51:42.017Z error: [BULLMQ WORKER EVENT - ERROR] Worker error for Job ID: N/A,
Name: N/A, ImportJobId: N/A. Error: connect ETIMEDOUT +10s
["Error: connect ETIMEDOUT\n at TLSSocket.<anonymous> (/Users/josevelez/Projects/gridl_queue_system/node_modules/ioredis/built/Redis.js:170:41)\n at Object.onceWrapper (node:events:627:28)\n at TLSSocket.emit (node:events:513:28)\n at Socket._onTimeout (node:net:609:8)\n at listOnTimeout (node:internal/timers:614:17)\n at process.processTimers (node:internal/timers:549:7)"]
Error: connect ETIMEDOUT
at TLSSocket.<anonymous> (/Users/josevelez/Projects/gridl_queue_system/node_modules/ioredis/built/Redis.js:170:41)
at Object.onceWrapper (node:events:627:28)
at TLSSocket.emit (node:events:513:28)
at Socket._onTimeout (node:net:609:8)
at listOnTimeout (node:internal/timers:614:17)
at process.processTimers (node:internal/timers:549:7) {
errorno: 'ETIMEDOUT',
code: 'ETIMEDOUT',
syscall: 'connect'
}
```
16 Replies
3 months ago
Hello,
You need to connect to the public host and port without TLS.
Best,
Brody
Status changed to Awaiting User Response Railway • 3 months ago
brody
Hello,You need to connect to the public host and port without TLS.Best,Brody
3 months ago
But that will incur egress fees. I was using the url provided under Settings -> Networking before and it worked. but today it stopped working.
Status changed to Awaiting Railway Response Railway • 3 months ago
3 months ago
any idea? I'm stuck and cannot connect to my redis instance from localhost.
3 months ago
I've tried everything with no luck. I tried setting family: 0 and family: 4 and still no luck. I'm using TLS.
im connecting with this custom method:
```
export function createBullMqConnectionOptions(
configService: ConfigService,
): ConnectionOptions {
const host = configService.get<string>('REDIS_HOST');
const port = configService.get<number>('REDIS_PORT');
const username = configService.get<string | undefined>('REDIS_USERNAME');
const password = configService.get<string | undefined>('REDIS_PASSWORD');
const familyEnvValue = configService.get<string | undefined>('REDIS_FAMILY');
let family: number = 0; // Default to 0 (IPv4 then IPv6)
if (familyEnvValue !== undefined) {
const parsedFamily = parseInt(familyEnvValue, 10);
if (!isNaN(parsedFamily) && [0, 4, 6].includes(parsedFamily)) {
family = parsedFamily;
} else {
logger.warn(
`Invalid REDIS_FAMILY value: "${familyEnvValue}". Expected "0", "4", or "6". Defaulting to ${family}.`,
);
}
}
const connectionOptions: ConnectionOptions = {
host,
port,
username: username || undefined, // Ensure undefined if empty string
password: password || undefined, // Ensure undefined if empty string
family,
// If host is not localhost, enable TLS and set servername to the host for SNI
tls: host !== 'localhost' ? { servername: host } : undefined,
};
```
3 months ago
Below is my console log:
025-05-07T19:25:57.959Z error: [BULLMQ WORKER EVENT - ERROR] Worker error for Job ID: N/A, Name: N/A, ImportJobId: N/A. Error: connect ETIMEDOUT +10s
["Error: connect ETIMEDOUT\n at TLSSocket.<anonymous> (/[redacted]/node_modules/ioredis/built/Redis.js:170:41)\n at Object.onceWrapper (node:events:627:28)\n at TLSSocket.emit (node:events:513:28)\n at Socket._onTimeout (node:net:609:8)\n at listOnTimeout (node:internal/timers:614:17)\n at process.processTimers (node:internal/timers:549:7)"]
Error: connect ETIMEDOUT
at TLSSocket.<anonymous> (/[redacted]/node_modules/ioredis/built/Redis.js:170:41)
at Object.onceWrapper (node:events:627:28)
at TLSSocket.emit (node:events:513:28)
at Socket._onTimeout (node:net:609:8)
at listOnTimeout (node:internal/timers:614:17)
at process.processTimers (node:internal/timers:549:7) {
errorno: 'ETIMEDOUT',
code: 'ETIMEDOUT',
syscall: 'connect'
}
2025-05-07T19:25:57.964Z error: [BULLMQ WORKER EVENT - ERROR] Worker error for Job ID: N/A, Name: N/A, ImportJobId: N/A. Error: connect ETIMEDOUT +5ms
["Error: connect ETIMEDOUT\n at TLSSocket.<anonymous> (/[redacted]/node_modules/ioredis/built/Redis.js:170:41)\n at Object.onceWrapper (node:events:627:28)\n at TLSSocket.emit (node:events:513:28)\n at Socket._onTimeout (node:net:609:8)\n at listOnTimeout (node:internal/timers:614:17)\n at process.processTimers (node:internal/timers:549:7)"]
joselvelez
I've tried everything with no luck. I tried setting family: 0 and family: 4 and still no luck. I'm using TLS.im connecting with this custom method:```export function createBullMqConnectionOptions( configService: ConfigService, ): ConnectionOptions { const host = configService.get<string>('REDIS_HOST'); const port = configService.get<number>('REDIS_PORT'); const username = configService.get<string | undefined>('REDIS_USERNAME'); const password = configService.get<string | undefined>('REDIS_PASSWORD'); const familyEnvValue = configService.get<string | undefined>('REDIS_FAMILY'); let family: number = 0; // Default to 0 (IPv4 then IPv6) if (familyEnvValue !== undefined) { const parsedFamily = parseInt(familyEnvValue, 10); if (!isNaN(parsedFamily) && [0, 4, 6].includes(parsedFamily)) { family = parsedFamily; } else { logger.warn( `Invalid REDIS_FAMILY value: "${familyEnvValue}". Expected "0", "4", or "6". Defaulting to ${family}.`, ); } } const connectionOptions: ConnectionOptions = { host, port, username: username || undefined, // Ensure undefined if empty string password: password || undefined, // Ensure undefined if empty string family, // If host is not localhost, enable TLS and set servername to the host for SNI tls: host !== 'localhost' ? { servername: host } : undefined, };```
3 months ago
What exactly are you passing as connection options to BullMQ?
https://docs.railway.com/reference/errors/enotfound-redis-railway-internal#using-bullmq
Does that not work?
Status changed to Awaiting User Response Railway • 3 months ago
ray-chen
What exactly are you passing as connection options to BullMQ?https://docs.railway.com/reference/errors/enotfound-redis-railway-internal#using-bullmqDoes that not work?
3 months ago
When I use this it works:
export function createBullMqConnectionOptions(
configService: ConfigService,
): ConnectionOptions {
const redisUrlString = configService.get<string>('REDIS_URL');
if (!redisUrlString) {
throw new Error('REDIS_URL is not defined in environment variables.');
}
const redisUrl = new URL(redisUrlString);
const host = redisUrl.hostname;
const port = Number(redisUrl.port);
const username = redisUrl.username || undefined;
const password = redisUrl.password || undefined;
const connectionOptions: ConnectionOptions = {
host,
port,
username,
password,
tls: redisUrl.protocol === 'rediss:' ? { servername: host } : undefined,
};
return connectionOptions;
}
but when I use this, it does not
export function createBullMqConnectionOptions(
configService: ConfigService,
): ConnectionOptions {
const host = configService.get<string>('REDIS_HOST');
const port = configService.get<number>('REDIS_PORT');
const username = configService.get<string | undefined>('REDIS_USERNAME');
const password = configService.get<string | undefined>('REDIS_PASSWORD');
const familyEnvValue = configService.get<string | undefined>('REDIS_FAMILY');
let family: number = 0; // Default to 0 (IPv4 then IPv6)
if (familyEnvValue !== undefined) {
const parsedFamily = parseInt(familyEnvValue, 10);
if (!isNaN(parsedFamily) && [0, 4, 6].includes(parsedFamily)) {
family = parsedFamily;
} else {
logger.warn(
`Invalid REDIS_FAMILY value: "${familyEnvValue}". Expected "0", "4", or "6". Defaulting to ${family}.`,
);
}
}
const connectionOptions: ConnectionOptions = {
host,
port,
username: username || undefined, // Ensure undefined if empty string
password: password || undefined, // Ensure undefined if empty string
family,
// If host is not localhost, enable TLS and set servername to the host for SNI
tls: host && host !== 'localhost' ? { servername: host } : undefined,
};
return connectionOptions;
}
The first is using the URL for public network
.env using REDIS_URL: redis://default:*******@switchback.proxy.rlwy.net:10998
My understanding is that using this url will incur egress charges
This works on my local machine
This does not work on my NestJS instance on Railway within the same project
I will continue in a new message due to character constraints...
Status changed to Awaiting Railway Response Railway • 3 months ago
3 months ago
Yes it will incur egress, but you cannot connect to the private domain from your own computer.
Status changed to Awaiting User Response Railway • 3 months ago
joselvelez
When I use this it works:export function createBullMqConnectionOptions( configService: ConfigService, ): ConnectionOptions { const redisUrlString = configService.get<string>('REDIS_URL'); if (!redisUrlString) { throw new Error('REDIS_URL is not defined in environment variables.'); } const redisUrl = new URL(redisUrlString); const host = redisUrl.hostname; const port = Number(redisUrl.port); const username = redisUrl.username || undefined; const password = redisUrl.password || undefined; const connectionOptions: ConnectionOptions = { host, port, username, password, tls: redisUrl.protocol === 'rediss:' ? { servername: host } : undefined, }; return connectionOptions; }but when I use this, it does notexport function createBullMqConnectionOptions( configService: ConfigService, ): ConnectionOptions { const host = configService.get<string>('REDIS_HOST'); const port = configService.get<number>('REDIS_PORT'); const username = configService.get<string | undefined>('REDIS_USERNAME'); const password = configService.get<string | undefined>('REDIS_PASSWORD'); const familyEnvValue = configService.get<string | undefined>('REDIS_FAMILY'); let family: number = 0; // Default to 0 (IPv4 then IPv6) if (familyEnvValue !== undefined) { const parsedFamily = parseInt(familyEnvValue, 10); if (!isNaN(parsedFamily) && [0, 4, 6].includes(parsedFamily)) { family = parsedFamily; } else { logger.warn( `Invalid REDIS_FAMILY value: "${familyEnvValue}". Expected "0", "4", or "6". Defaulting to ${family}.`, ); } } const connectionOptions: ConnectionOptions = { host, port, username: username || undefined, // Ensure undefined if empty string password: password || undefined, // Ensure undefined if empty string family, // If host is not localhost, enable TLS and set servername to the host for SNI tls: host && host !== 'localhost' ? { servername: host } : undefined, }; return connectionOptions; }The first is using the URL for public network.env using REDIS_URL: redis://default:*******@switchback.proxy.rlwy.net:10998My understanding is that using this url will incur egress chargesThis works on my local machineThis does not work on my NestJS instance on Railway within the same projectI will continue in a new message due to character constraints...
3 months ago
The second is using the address found under REDIS -> Settings -> Networking -> Public Networking
.env using
REDIS_HOST: switchback.proxy.rlwy.net:10998
REDIS_PORT: 10998
REDIS_USERNAME: default
REDIS_PASSWORD: ******
REDIS_FAMILY: 0
This did not work on my local machine
This did work (for a while) on my Railway NestJS instance within the same project.
What I do not understand:
What is this address for? Can I not connect from my local machine with this?
I am confused with the different urls available.
Attachments
Status changed to Awaiting Railway Response Railway • 3 months ago
3 months ago
That is the public host and public port (5 digit number).
The data tab uses those to connect, if the data tab can connect the database is publicly accessible and is working as intended.
Status changed to Awaiting User Response Railway • 3 months ago
brody
That is the public host and public port (5 digit number).The data tab uses those to connect, if the data tab can connect the database is publicly accessible and is working as intended.
3 months ago
Ok, so how do I get my NestJS instance in the same project to connect successfully without using the pubic address that incurs egress charges? My NestJS instance keeps crashing
Status changed to Awaiting Railway Response Railway • 3 months ago
Status changed to Awaiting User Response Railway • 3 months ago
3 months ago
No, that uses the PUBLIC address that incurs egress charges. I want to connect INTERNALLY within the same project.
Status changed to Awaiting Railway Response Railway • 3 months ago
3 months ago
I am able to connect from local machine now, but my NestJS instance in my railway project continues to crash. I've tried all the different hosts with no success.
redis
${{ Redis.REDIS_URL }}
redis://default:*****@redis.railway.internal:6379
redis.railway.internal
None of these is working
3 months ago
The example code in Ray's link is to help you use BullMQ with the private network.
Status changed to Awaiting User Response Railway • 3 months ago
3 months ago
Ok, I have it all working now on local and within the project. For anyone else that might struggle with this, I used this custom helper to handle the connection based on the environment, since you basically have two different configs (one for private on Railway and one for public when on local machine).
Below is the helper method I used inside my NestJS Project
import IORedis, { RedisOptions } from 'ioredis';
import { ConfigService } from '@nestjs/config';
import { Logger } from '@nestjs/common';
import { URL } from 'url';
export function createBullMqConnection(configService: ConfigService): IORedis {
const isLocal = process.env.NODE_ENV === 'development';
if (isLocal) {
const redisUrlString = configService.get<string>('REDIS_URL_PUBLIC');
if (!redisUrlString) {
throw new Error(
'REDIS_URL_PUBLIC is not defined in environment variables.',
);
}
const redisUrl = new URL(redisUrlString);
const options: RedisOptions = {
host: redisUrl.hostname,
port: Number(redisUrl.port),
username: redisUrl.username || undefined,
password: redisUrl.password || undefined,
tls:
redisUrl.protocol === 'rediss:'
? { servername: redisUrl.hostname }
: undefined,
maxRetriesPerRequest: null,
};
Logger.log(
`Using EXTERNAL Redis connection (Host: ${options.host}, Port: ${options.port}, TLS: ${!!options.tls})`,
);
return new IORedis(options);
} else {
const redisUrlString = configService.get<string>('REDIS_URL_PRIVATE');
if (!redisUrlString) {
throw new Error(
'REDIS_URL_PRIVATE is not defined in environment variables.',
);
}
const redisUrl = new URL(redisUrlString);
const options: RedisOptions = {
host: redisUrl.hostname,
port: Number(redisUrl.port),
family: 0, // IPv4/IPv6 Dual Stack Lookup
username: redisUrl.username || undefined,
password: redisUrl.password || undefined,
maxRetriesPerRequest: null,
};
Logger.log(
`Using INTERNAL Redis connection (Host: ${options.host}, Port: ${options.port})`,
);
return new IORedis(options);
}
}
I saved this to a git repo with some documentation for anyone that wants to use it. I hope this helps.
https://github.com/joselvelez/railway_redis_bullmq_connection_helper/tree/main
If I made any mistakes, please let me know.
Status changed to Awaiting Railway Response Railway • 3 months ago
Status changed to Solved joselvelez • 3 months ago