redis / node-redis

Redis Node.js client
https://redis.js.org/
MIT License
16.87k stars 1.87k forks source link

SocketClosedUnexpectedlyError: Socket closed unexpectedly #2032

Closed wyvasi closed 2 years ago

wyvasi commented 2 years ago

Good day! The socket connection closes unexpectedly and doesn't reconnect, my older version of node-redis(2.8.0) was reconnecting fine and still does. After reconnect it doesn't print ready anymore. We are using AWS ElastiCache. I can only reproduce this on production env. We have a package that wraps node-redis and is used in all our apps, so I don't think is related to version difference. I tried to comment out next code and it doesn't close the connection at all (from @socket.io/redis-adapter).

this.subClient.pSubscribe(this.channel + "*", (msg, channel) => {
    this.onmessage(null, channel, msg);
}, true);
Redis connected
Redis ready!
Redis connected
Redis ready!
fetch error Error: timeout reached while waiting for fetchSockets response
    at Timeout._onTimeout (C:\work\test-socket\node_modules\@socket.io\redis-adapter\dist\index.js:615:28)
    at listOnTimeout (node:internal/timers:568:17)
    at processTimers (node:internal/timers:510:7)
List with sockets connected to hello room: 0
List with sockets connected to hello room: 5
SocketClosedUnexpectedlyError: Socket closed unexpectedly
    at Socket.<anonymous> (C:\work\test-socket\node_modules\@node-redis\client\dist\lib\client\socket.js:195:118)
    at Object.onceWrapper (node:events:510:26)
    at Socket.emit (node:events:390:28)
    at TCP.<anonymous> (node:net:687:12)
Redis reconnecting
Redis connected
ParserError: Protocol error, got "n" as reply type byte
    at handleError (C:\work\test-socket\node_modules\redis-parser\lib\parser.js:190:15)
    at parseType (C:\work\test-socket\node_modules\redis-parser\lib\parser.js:304:14) {
  offset: 304,
  buffer: '....'

Here is where I catch the parser error: client/socket.ts

if (this.#initiator) {
            try {
                await this.#initiator();
            } catch (err) {

List with buffers and offsets:

[{
        offset: 405,
        buffer: '{"type":"Buffer","data":[42,52,13,10,36,56,13,10,112,109,101,115,115,97,103,101,13,10,36,49,50,13,10,105,110,116,101,114,97,99,116,35,47,35,42,13,10,36,54,52,13,10,105,110,116,101,114,97,99,116,35,47,35,104,105,115,82,111,111,109,114,104,122,78,49,49,74,80,98,111,113,107,54,120,78,103,80,52,100,121,71,102,106,84,120,75,86,115,121,98,88,106,107,108,56,56,45,50,66,119,76,65,112,73,99,35,13,10,36,49,53,53,13,10,147,166,119,65,102,98,82,66,131,164,116,121,112,101,2,164,100,97,116,97,146,173,110,111,116,105,102,105,99,97,116,105,111,110,115,130,165,99,111,117,110,116,205,5,184,164,116,121,112,101,181,110,111,116,105,102,105,99,97,116,105,111,110,115,95,99,111,117,110,116,101,114,163,110,115,112,161,47,131,165,114,111,111,109,115,145,217,52,104,105,115,82,111,111,109,114,104,122,78,49,49,74,80,98,111,113,107,54,120,78,103,80,52,100,121,71,102,106,84,120,75,86,115,121,98,88,106,107,108,56,56,45,50,66,119,76,65,112,73,99,166,101,120,99,101,112,116,144,165,102,108,97,103,115,128,13,10,42,52,13,10,36,56,13,10,112,109,101,115,115,97,103,101,13,10,36,49,50,13,10,105,110,116,101,114,97,99,116,35,47,35,42,13,10,36,54,52,13,10,105,110,116,101,114,97,99,116,35,47,35,104,105,115,82,111,111,109,100,76,57,116,118,98,120,51,84,118,52,114,56,87,114,109,56,83,78,89,50,71,53,110,98,80,114,97,112,85,70,116,71,50,107,74,76,116,90,45,50,66,57,105,85,35,13,10,36,49,53,51,13,10,147,166,119,65,102,98,82,66,131,164,116,121,112,101,2,164,100,97,116,97,146,173,110,111,116,105,102,105,99,97,116,105,111,110,115,130,165,99,111,117,110,116,110,164,116,121,112,101,181,110,111,116,105,102,105,99,97,116,105,111,110,115,95,99,111,117,110,116,101,114,163,110,115,112,161,47,131,165,114,111,111,109,115,145,217,52,104,105,115,82,111,111,109,100,76,57,116,118,98,120,51,84,118,52,114,56,87,114,109,56,83,78,89,50,71,53,110,98,80,114,97,112,85,70,116,71,50,107,74,76,116,90,45,50,66,57,105,85,166,101,120,99,101,112,116,144,165,102,108,97,103,115,128,13,10,42,52,13,10,36,56,13,10,112,109,101,115,115,97,103,101,13,10,36,49,50,13,10,105,110,116,101,114,97,99,116,35,47,35,42,13,10,36,54,50,13,10,105,110,116,101,114,97,99,116,35,47,35,104,105,115,82,111,111,109,120,89,112,113,90,54,101,111,89,48,107,120,90,105,81,86,113,97,111,89,90,99,69,119,121,72,50,100,70,122,78,115,108,52,82,50,114,122,111,109,85,113,107,35,13,10,36,49,53,49,13,10,147,166,119,65,102,98,82,66,131,164,116,121,112,101,2,164,100,97,116,97,146,173,110,111,116,105,102,105,99,97,116,105,111,110,115,130,165,99,111,117,110,116,113,164,116,121,112,101,181,110,111,116,105,102,105,99,97,116,105,111,110,115,95,99,111,117,110,116,101,114,163,110,115,112,161,47,131,165,114,111,111,109,115,145,217,50,104,105,115,82,111,111,109,120,89,112,113,90,54,101,111,89,48,107,120,90,105,81,86,113,97,111,89,90,99,69,119,121,72,50,100,70,122,78,115,108,52,82,50,114,122,111,109,85,113,107,166,101,120,99,101,112,116,144,165,102,108,97,103,115,128,13,10,42,52,13,10,36,56,13,10,112,109,101,115,115,97,103,101,13,10,36,49,50,13,10,105,110,116,101,114,97,99,116,35,47,35,42,13,10,36,54,50,13,10,105,110,116,101,114,97,99,116,35,47,35,104,105,115,82,111,111,109,53,111,74,87,66,49,70,85,50,108,109,86,73,54,55,70,106,68,99,83,103,71,118,121,68,48,76,66,83,90,67,83,97,67,113,103,97,69,115,86,119,120,85,35,13,10,36,49,53,50,13,10,147,166,119,65,102,98,82,66,131,164,116,121,112,101,2,164,100,97,116,97,146,173,110,111,116,105,102,105,99,97,116,105,111,110,115,130,165,99,111,117,110,116,204,203,164,116,121,112,101,181,110,111,116,105,102,105,99,97,116,105,111,110,115,95,99,111,117,110,116,101,114,163,110,115,112,161,47,131,165,114,111,111,109,115,145,217,50,104,105,115,82,111,111,109,53,111,74,87,66,49,70,85,50,108,109,86,73,54,55,70,106,68,99,83,103,71,118,121,68,48,76,66,83,90,67,83,97,67,113,103,97,69,115,86,119,120,85,166,101,120,99,101,112,116,144,165,102,108,97,103,115,128,13,10,42,52,13,10,36,56,13,10,112,109,101,115,115,97,103,101,13,10,36,49,50,13,10,105,110,116,101,114,97,99,116,35,47,35,42,13,10,36,54,52,13,10,105,110,116,101,114,97,99,116,35,47,35,104,105,115,82,111,111,109,53,85,74,71,49,53,87,110,116,103,79,88,115,116,106,115,49,45,50,66,82,66,76,106,72,102,82,68,65,109,115,122,112,98,114,82,86,82,69,102,73,50,105,53,85,35,13,10,36,49,53,52,13,10,147,166,119,65,102,98,82,66,131,164,116,121,112,101,2,164,100,97,116,97,146,173,110,111,116,105,102,105,99,97,116,105,111,110,115,130,165,99,111,117,110,116,204,155,164,116,121,112,101,181,110,111,116,105,102,105,99,97,116,105,111,110,115,95,99,111,117,110,116,101,114,163,110,115,112,161,47,131,165,114,111,111,109,115,145,217,52,104,105,115,82,111,111,109,53,85,74,71,49,53,87,110,116,103,79,88,115,116,106,115,49,45,50,66,82,66,76,106,72,102,82,68,65,109,115,122,112,98,114,82,86,82,69,102,73,50,105,53,85,166,101,120,99,101,112,116,144,165,102,108,97,103,115,128,13,10]}'
    },
    {
        offset: 136,
        buffer: '{"type":"Buffer","data":[42,51,13,10,36,57,13,10,115,117,98,115,99,114,105,98,101,13,10,36,49,57,13,10,105,110,116,101,114,97,99,116,45,114,101,113,117,101,115,116,35,47,35,13,10,58,49,13,10,42,51,13,10,36,57,13,10,115,117,98,115,99,114,105,98,101,13,10,36,50,48,13,10,105,110,116,101,114,97,99,116,45,114,101,115,112,111,110,115,101,35,47,35,13,10,58,50,13,10,42,51,13,10,36,57,13,10,115,117,98,115,99,114,105,98,101,13,10,36,50,55,13,10,105,110,116,101,114,97,99,116,45,114,101,115,112,111,110,115,101,35,47,35,88,115,52,75,106,79,35,13,10,58,51,13,10,42,51,13,10,36,57,13,10,115,117,98,115,99,114,105,98,101,13,10,36,50,52,13,10,105,110,116,101,114,97,99,116,45,114,101,113,117,101,115,116,35,47,97,100,109,105,110,35,13,10,58,52,13,10,42,51,13,10,36,57,13,10,115,117,98,115,99,114,105,98,101,13,10,36,50,53,13,10,105,110,116,101,114,97,99,116,45,114,101,115,112,111,110,115,101,35,47,97,100,109,105,110,35,13,10,58,53,13,10,42,51,13,10,36,57,13,10,115,117,98,115,99,114,105,98,101,13,10,36,51,50,13,10,105,110,116,101,114,97,99,116,45,114,101,115,112,111,110,115,101,35,47,97,100,109,105,110,35,104,65,112,66,90,76,35,13,10,58,54,13,10,42,51,13,10,36,49,48,13,10,112,115,117,98,115,99,114,105,98,101,13,10,36,49,50,13,10,105,110,116,101,114,97,99,116,35,47,35,42,13,10,58,55,13,10,42,51,13,10,36,49,48,13,10,112,115,117,98,115,99,114,105,98,101,13,10,36,49,55,13,10,105,110,116,101,114,97,99,116,35,47,97,100,109,105,110,35,42,13,10,58,56,13,10]}'
    },
    {
        offset: 12,
        buffer: '{"type":"Buffer","data":[42,52,13,10,36,56,13,10,112,109,101,115,115,97,103,101,13,10,36,49,50,13,10,105,110,116,101,114,97,99,116,35,47,35,42,13,10,36,54,56,13,10,105,110,116,101,114,97,99,116,35,47,35,104,105,115,82,111,111,109,90,71,86,107,121,121,84,115,98,77,84,45,50,66,111,76,53,69,104,82,106,69,121,81,78,116,48,100,69,57,99,66,52,45,50,70,54,67,90,76,113,81,113,45,50,66,117,81,119,35,13,10,36,49,53,56,13,10,147,166,119,65,102,98,82,66,131,164,116,121,112,101,2,164,100,97,116,97,146,173,110,111,116,105,102,105,99,97,116,105,111,110,115,130,165,99,111,117,110,116,204,131,164,116,121,112,101,181,110,111,116,105,102,105,99,97,116,105,111,110,115,95,99,111,117,110,116,101,114,163,110,115,112,161,47,131,165,114,111,111,109,115,145,217,56,104,105,115,82,111,111,109,90,71,86,107,121,121,84,115,98,77,84,45,50,66,111,76,53,69,104,82,106,69,121,81,78,116,48,100,69,57,99,66,52,45,50,70,54,67,90,76,113,81,113,45,50,66,117,81,119,166,101,120,99,101,112,116,144,165,102,108,97,103,115,128,13,10]}'
    },
    {
        offset: 88,
        buffer: '{"type":"Buffer","data":[42,52,13,10,36,56,13,10,112,109,101,115,115,97,103,101,13,10,36,49,50,13,10,105,110,116,101,114,97,99,116,35,47,35,42,13,10,36,54,56,13,10,105,110,116,101,114,97,99,116,35,47,35,104,105,115,82,111,111,109,89,111,97,115,90,54,72,53,80,45,50,66,71,45,50,66,80,45,50,66,80,49,90,106,82,87,74,87,87,83,54,113,72,74,50,86,120,80,77,68,78,51,117,81,101,120,75,87,81,35,13,10,36,49,53,56,13,10,147,166,104,55,52,78,66,121,131,164,116,121,112,101,2,164,100,97,116,97,146,173,110,111,116,105,102,105,99,97,116,105,111,110,115,130,165,99,111,117,110,116,204,194,164,116,121,112,101,181,110,111,116,105,102,105,99,97,116,105,111,110,115,95,99,111,117,110,116,101,114,163,110,115,112,161,47,131,165,114,111,111,109,115,145,217,56,104,105,115,82,111,111,109,89,111,97,115,90,54,72,53,80,45,50,66,71,45,50,66,80,45,50,66,80,49,90,106,82,87,74,87,87,83,54,113,72,74,50,86,120,80,77,68,78,51,117,81,101,120,75,87,81,166,101,120,99,101,112,116,144,165,102,108,97,103,115,128,13,10]}'
    }]

Code for creating the client

const Redis = require('redis');
Redis.debug_mode = true;

const getClient = async (url) => {

    const client = Redis.createClient({
        socket: {
            host: url
            port: 6379,
        }
    });
    client.on('error', (err) => {
        console.error(err);
    });
    client.on('connect', () => {
        console.log('Redis connected');
    });
    client.on('reconnecting', () => {
        console.log('Redis reconnecting');
    });
    client.on('ready', () => {
        console.log('Redis ready!');
    });

    await client.connect();
    return client;
};

module.exports = {
    getClient,
};

Environment:

wyvasi commented 2 years ago

After disconnect/reconnect it stops receiving messages. With the older version of node-redis it was reconnecting without any problems. I added some code to print the parser error.

Code:

const { getClient } = require('./libs/redis');
const { redisUrl, key } = require('./config');

const start = async () => {
    const client = await getClient(redisUrl);
    client.pSubscribe(key + '#/#*', (msg, channel) => {
        onmessage();
    }, true);
    client.pSubscribe( key + '#/admin#*', (msg, channel) => {
        onmessage();
    }, true);
};

start().catch(err => console.log(err));

let x = 0;
const onmessage = (channel, msg) => {
    x++;
};

setInterval(() => {console.log(`Got ${x} messages!`)}, 5000);
const Redis = require('redis');

const onRedisError = (err) => {console.error(err)};
const onRedisConnect = () => {console.log('Redis connected')};
const onRedisReconnecting = () => {console.log('Redis reconnecting')};
const onRedisReady = () => {console.log('Redis ready!')};

const getClient = async (url) => {
    const client = Redis.createClient({
        socket: {
            host: url.replace('redis://', '').replace(':6379', ''),
            port: 6379,
        }
    });
    client.on('error', onRedisError);
    client.on('connect', onRedisConnect);
    client.on('reconnecting', onRedisReconnecting);
    client.on('ready', onRedisReady);

    await client.connect();
    return client;
};

module.exports = {
    getClient,
};

Output:

Redis connected
Redis ready!
Got 261 messages!
Got 1751 messages!
Got 3573 messages!
Got 5616 messages!
Got 8532 messages!
Got 9348 messages!
Got 9623 messages!
Got 10069 messages!
Got 11630 messages!
Got 11828 messages!
Got 12844 messages!
Got 14737 messages!
SocketClosedUnexpectedlyError: Socket closed unexpectedly
    at Socket.<anonymous> (C:\work\test-socket\node_modules\@node-redis\client\dist\lib\client\socket.js:196:118)
    at Object.onceWrapper (node:events:510:26)
    at Socket.emit (node:events:390:28)
    at TCP.<anonymous> (node:net:687:12)
Redis reconnecting
Redis connected
ParserError: Protocol error, got "e" as reply type byte
    at handleError (C:\work\test-socket\node_modules\redis-parser\lib\parser.js:190:15)
    at parseType (C:\work\test-socket\node_modules\redis-parser\lib\parser.js:304:14) {
  offset: 358,
  buffer: '{"type":"Buffer","data":[42,52,13,10,36,56,13,10,112,109,101,11.......
}
Got 16116 messages!
Got 16116 messages!
Got 16116 messages!
Got 16116 messages!
Got 16116 messages!
Got 16116 messages!
Got 16116 messages!
Got 16116 messages!
Got 16116 messages!
rpong commented 2 years ago

We are currently stuck with v3 for months now because this issue seems to be still unresolved with v4.

erajanraja24 commented 2 years ago

@rpong Could you please update the tentative ETA for this issue as it is a blocker for v4?

rpong commented 2 years ago

@rpong Could you please update the tentative ETA for this issue as it is a blocker for v4?

Hi @erajanraja24, @leibale would be the best person to ask, I am not part of the team..

1nstinct commented 2 years ago

Hey guys @leibale. Any updates on this fix for this issue?

leibale commented 2 years ago

This code does not reproduce the issue (I'm running docker restart while the code is running)

import { createClient } from '@node-redis/client';

async function client() {
    const client = createClient();

    client.on('error', err => console.error('client error', err));
    client.on('connect', () => console.log('client is connect'));
    client.on('reconnecting', () => console.log('client is reconnecting'));
    client.on('ready', () => console.log('client is ready'));

    await client.connect();

    return client;
}

const [subscriber, publisher] = await Promise.all([
    client(),
    client()
]);

let counter = 0;
subscriber.pSubscribe('*', () => counter++);
setInterval(() => console.log(`Got ${counter} messages!`), 1000);

setInterval(async () => {
    try {
        await publisher.publish('channel', 'message');
    } catch (err) {
        console.error('publish error', err);
    }
}, 5);
client error Error: connect ECONNREFUSED 127.0.0.1:6379
    at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1146:16) {
  errno: -111,
  code: 'ECONNREFUSED',
  syscall: 'connect',
  address: '127.0.0.1',
  port: 6379
}
client is reconnecting
client is reconnecting
client is connect
client is connect
client is ready
Got 484 messages!
Got 484 messages!
client is ready
Got 677 messages!
Got 868 messages!
rpong commented 2 years ago

@leibale i just tested 4.1.0 and it seems this issue still persists, reconnecting still doesn't work like it used to like in v3. after "Socket closed unexpectedly", it just doesn't reconnect without restarting the client application. We simulate this by restarting redis (docker) while the application is running.

leibale commented 2 years ago

https://github.com/redis/node-redis/issues/1985#issuecomment-1116865925

rpong commented 2 years ago
    client.on('error', err => console.error('client error', err));
    client.on('connect', () => console.log('client is connect'));
    client.on('reconnecting', () => console.log('client is reconnecting'));
    client.on('ready', () => console.log('client is ready'));

Thanks @leibale , i have discovered that this IS working if we do following before the "await client.connect();"

client.on('error', err => console.log('client error', err));
client.on('connect', () => console.log('client is connect'));
client.on('reconnecting', () => console.log('client is reconnecting'));
client.on('ready', () => console.log('client is ready'));

but without the above, it doesn't reconnect like v3 does. We can upgrade now and just pass debug info for the above, but would like to confirm if this is the intended behavior.

leibale commented 2 years ago

client.on('error') was required in v3 as well (see https://nodejs.org/api/events.html#error-events)

rpong commented 2 years ago

https://nodejs.org/api/events.html#error-events

In our case, we did not have this at all for v3 but reconnecting was working.

Thank you for the info, we can finally upgrade to v4 after many months.

cheesecakeassassin commented 2 years ago

I can confirm that the code above that @leibale provided fixes the issue! My issue in particular was that I had deployed my app using Redis to Heroku and upon the socket closing unexpectedly, the Heroku-deployed app would crash until I redeployed it. The problem was driving me nuts and this was the only solution on the web that fixed it. Thank you!

KunalBurangi commented 2 years ago

@leibale , The issue persists in v4 and yes it does reconnect. but is there any particular reason why is it crashing unexpectedly? yes we do have load-balancer and proxies like gateway and Nginx

derikb commented 2 years ago

Just had this occur for us with 4.1.0 running...

Code:

const pubClient = createClient(config);
    const subClient = pubClient.duplicate();

    pubClient.on('connect', () => { chatlogger.error('Redis pub adapter connect'); });
    pubClient.on('ready', () => { chatlogger.error('Redis pub adapter ready'); });
    pubClient.on('end', () => { chatlogger.error('Redis pub adapter end'); });
    pubClient.on('reconnecting', () => { chatlogger.error('Redis pub adapter reconnecting'); });
    pubClient.on('error', (err) => {
        chatlogger.error('Redis pub adapter error', err);
    });

    subClient.on('connect', () => { chatlogger.error('Redis sub adapter connect'); });
    subClient.on('ready', () => { chatlogger.error('Redis sub adapter ready'); });
    subClient.on('end', () => { chatlogger.error('Redis sub adapter end'); });
    subClient.on('reconnecting', () => { chatlogger.error('Redis sub adapter reconnecting'); });
    subClient.on('error', (err) => {
        chatlogger.error('Redis sub adapter error', err);
    });

    await pubClient.connect();
    await subClient.connect();

Our logging:

2022-05-17 13:58:01 error: Redis sub adapter error: SocketClosedUnexpectedlyError: Socket closed unexpectedly
2022-05-17 13:58:01 error: Redis sub adapter reconnecting: ''
2022-05-17 13:58:01 error: Redis sub adapter connect: ''

The ready event didn't ever happen. When I restarted node it did connect/ready.

Any other ideas/tips? Something I'm missing? This is for a socket.io adaptor so the redis connection going down really messes with the rest of our app.

derikb commented 2 years ago

I should add I was getting the ready event in dev testing if I just stopped/started redis. It seems to still be a problem for whatever is happening when the socket closes unexpectedly. (In my case via an AWS Elasticache.

ryanmeador commented 2 years ago

I believe I'm experiencing this issue on 4.2.0. I set my event listeners like this:

  client.on('error', err => log.error(`Redis error: ${err}`));
  client.on('reconnecting', params => log.info(`Redis reconnecting, attempt ${params.attempt}`));
  client.on('connect', () => log.info('Redis connected'));
  client.on('ready', () => log.info('Redis ready'));
  client.on('end', () => log.info('Redis connection closed'));

When it starts up, I see this in the log:

INFO redis: Redis connected
INFO redis: Redis ready

After a while, it disconnects. I'm using Heroku's Redis server, which seems to drop connections after a few minutes, I think in an attempt to clean up stale connections. Before upgrading from 3.x.x, it would reconnect seamlessly. Now, all I see is this:

ERROR redis: Redis error: Error: Socket closed unexpectedly

No reconnect, no ready. I have to restart my Node process to get it working again. Can you offer any advice?

ryanmeador commented 2 years ago

I think I have discovered the cause of my problem. I was expecting a params object to be passed to my reconnect event handler, but this was apparently removed in v4. Since my handler was now accessing an undefined property, it was throwing an error at runtime. This error was silently swallowed, but still prevented the reconnection. Could you please log errors of this nature, and still continue with the reconnect? No doubt it will help others in the future who face a similar problem.

leibale commented 2 years ago

@ryanmeador can you please open a new issue with reproduction?

inapeace0 commented 2 years ago

Hi, I got this same issue on heroku and I changed to the latest version(4.2.0), and still got the same issue after some minutes.

This is my code.

import { createClient } from 'redis';
import config from 'config'

const redisUrl = config.get<string>("redisUrl");

const redisClient = createClient({
  url: redisUrl,
});

const connectRedis = async () => {
  try {
    await redisClient.connect();
    console.log('Redis client connect successfully');
    redisClient.set('try', 'Hello Welcome to Express with TypeORM');
  } catch (error) {
    console.log(error);
    setTimeout(connectRedis, 5000);
  }
};

connectRedis();

export default redisClient;

Is there a solution for this? Or maybe I rewrite the code?

leibale commented 2 years ago

@CaCaBlocker the only known bug that can cause this issue is the one @ryanmeador pointed out in this comment, and I'm already working to fix it (see this branch).

Other than that, this error could be caused by some kind of a proxy or a load balancer between the redis-server and the node server.

Without a reproduction I won't be able to debug and hopefully solve it.

bmiller59 commented 2 years ago

For anyone still having this issue, I can confirm that adding this code before creating connection resolved the issue for us.

    client.on('error', err => console.error('client error', err));
    client.on('connect', () => console.log('client is connect'));
    client.on('reconnecting', () => console.log('client is reconnecting'));
    client.on('ready', () => console.log('client is ready'));

But I also had to make sure that I had removed any other client error listeners that were re-throwing the error (or any other error).

polearnik commented 1 year ago

also you need to add listeners to publishers and subscribers

MartinSchere commented 1 year ago

I cannot confirm that this issue is fixed:

    const client = createClient({
      url: configService.get('SCROLLS_TX_REDIS_URL'),
      socket: {
        reconnectStrategy: (retries) => {
          console.log('RETRYING');
          return Math.min(retries * 100, 1000);
        },
        connectTimeout: configService.get('REDIS_CONNECT_TIMEOUT'),
      },
    });
    await client.connect();

Randomly disconnects and never logs RETRYING.

flashtheman commented 1 year ago

I'm facing the same issue. I use Redis version 6.0.

leibale commented 1 year ago

@flashtheman where is your redis server hosted? what version of node-redis are you using?

jorenvandeweyer commented 1 year ago

@leibale

Seeing the same on a managed redis db on digitalocean after upgrading.

Redis 6 node-redis: 4.5.1

leibale commented 1 year ago

@jorenvandeweyer sorry for that late response

I never used digitalocean managed redis, but maybe they do the same as azure and close idle connections? try the new pingInterval option (see https://github.com/redis/node-redis/blob/master/docs/client-configuration.md)

Nekidev commented 1 year ago

Same issue here. Just installed, worked for a while and suddenly started conecting, disconncting and reconnecting without being able to do nothing.

ahmedalmulki commented 1 year ago

I have the same issue in GKE : Redis: 7 node-redis: 4.5.1

leibale commented 1 year ago

@Nekidev @ahmedalmulki when this error occurs it's probably because:

  1. some proxies close idle connections, see this comment
  2. if the number of clients is bigger than CONFIG GET maxclients, the server will close some clients. you can check that using INFO CLIENTS.
derikb commented 1 year ago

fwiw my issue was not that the connection was closing, it was that the reconnection wasn't finishing. That seems like what a lot of people are reporting, contra this issue title, the original issue was "After reconnect it doesn't print ready anymore." which is what I was seeing. I don't think we can avoid connections closing for various reasons some time, but recovering from those closed connections is what still has me on the old version.

leibale commented 1 year ago

@derikb I've tried to stop and start the server process and to use the CLIENT KILL command, in both cases the client recovers. If you can help me reproduce the issue it'll be awsome :)

derikb commented 1 year ago

@leibale yeah that's the issue I had (see further up the thread https://github.com/redis/node-redis/issues/2032#issuecomment-1128975739 ). Manually stopping redis didn't trigger it. I couldn't figure out how to trigger it in dev, but it happened a few times in production (with AWS ElasticCache is was nigh impossible to figure out what had caused it). It was always that the ready event just wouldn't get triggered across any of the connections... just the unexpected close error, the reconnecting, the connect... then nothing.

leibale commented 1 year ago

@derikb you posted your comment before this comment, so maybe the problem you faced is already fixed?

derikb commented 1 year ago

@leibale I don't think so. I wasn't expecting or using any args on the reconnect handler. I was just logging that the event happened. And that log entry was getting logged.

leibale commented 1 year ago

@derikb maybe the changes in #2295 fixed it? if you have a staging server that you can test it on it'll be very helpful :)

derikb commented 1 year ago

@leibale any ideas on how I get redis to unexpectedly close that isn't just a stop/start? I tried that and it would not recreate the original issue. I assume cause the stop process closes connections in an orderly way

leibale commented 1 year ago

@derikb

  1. Restart the server
  2. CLIENT KILL command
  3. Disable network on the machine (if the Redis server is remote)
  4. If your client is behind some kind of a proxy/load balancer - in some of them you can configure "max idle time" (for example in azure it's 10 minutes and there is no way to change it).
  5. set maxclients in redis, and create more clients then configured (see https://redis.io/docs/reference/clients/)

I guess there are more ways, but these are the ones I currently have in mind...

fabioselau077 commented 1 year ago

@leibale

Seeing the same on a managed redis db on digitalocean after upgrading.

Redis 6 node-redis: 4.5.1

same, using redis db on digitalocean How to fixe?

leibale commented 1 year ago

@fabioselau077 @jorenvandeweyer https://www.digitalocean.com/community/questions/idle-redis-connection-reconnects-every-five-minutes try to set pingInterval to a value lower than 5 minutes (4 * 60 * 1000 should do it)

ilhmyz commented 1 year ago

@fabioselau077 using redis db on digitalocean try to set TLS to true see https://github.com/redis/node-redis/blob/master/docs/client-configuration.md#TLS

HenonoaH commented 1 year ago

Hi, I got this same issue on heroku and I changed to the latest version(4.2.0), and still got the same issue after some minutes.

This is my code.

import { createClient } from 'redis';
import config from 'config'

const redisUrl = config.get<string>("redisUrl");

const redisClient = createClient({
  url: redisUrl,
});

const connectRedis = async () => {
  try {
    await redisClient.connect();
    console.log('Redis client connect successfully');
    redisClient.set('try', 'Hello Welcome to Express with TypeORM');
  } catch (error) {
    console.log(error);
    setTimeout(connectRedis, 5000);
  }
};

connectRedis();

export default redisClient;

Is there a solution for this? Or maybe I rewrite the code?

@CaCaBlocker I having the same issue from Redis hosted in Heroku. Did you get any solution or workaround for this?

polearnik commented 1 year ago

@HenonoaH try to add listeners to all available events like ready reconnect error etc.

HenonoaH commented 1 year ago

@polearnik I have already added all the event listeners. I like to know if that exception is standard. I have configured Rollbar for my app and getting an exception log every five minutes!! This happens after the upgrade.

leonardovenoso commented 1 year ago

Changing to redis-server version 6 on Ubuntu and Nodejs Redis 4.6.6 it works fine. NestJS example:

import { Module } from '@nestjs/common'; import { createClient } from 'redis'; import { ConfigService } from '@nestjs/config';

@Module({ providers: [ { inject: [ConfigService], provide: 'REDIS_CLIENT', useFactory: async (configService: ConfigService) => { const redisCli = createClient({ url: redis://${configService.get('REDIS_USER')}:${configService.get('REDIS_PASSWORD')}@${configService.get('REDIS_HOST')}:${configService.get('REDIS_PORT')}, });

    redisCli.on('connect', () => {
      console.log('Connected to Redis');
    });

    redisCli.on('error', (err) => {
      console.log(err.message);
    });

    redisCli.on('ready', () => {
      console.log('Redis is ready');
    });

    redisCli.on('reconnecting', () => {
      console.log('client is reconnecting')
    });

    redisCli.on('end', () => {
      console.log('Redis connection ended');
    })

    process.on('SIGINT', () => {
      redisCli.quit();
    });

    return redisCli;
  }
}

], exports: ['REDIS_CLIENT'], }) export class RedisCliModule {}

hieuhuynhh commented 1 year ago

@fabioselau077 @jorenvandeweyer https://www.digitalocean.com/community/questions/idle-redis-connection-reconnects-every-five-minutes try to set pingInterval to a value lower than 5 minutes (4 * 60 * 1000 should do it)

Hi @leibale, I'm using ioredis and i don't see pingInterval option. How can i solve it with ioredis? Thanks.

leibale commented 1 year ago

@hieuhuynhh a simple setInterval should fix it:

const timer = setInterval(async () => {
  try {
    await client.ping();
  } catch (err) {
    console.error('Ping Interval Error', err);
  }
}, 1000 * 60 * 4);

// make sure to `clearInterval` when you close the client
clearInterval(timer);
client.disconnect();
niksy commented 1 year ago

Although documentation mentions setting handler for error event, it is not clear that this is actually needed to have this issue fixed. There weren’t any errors of this kind in v3.

Is there a reason why this happens in v4? Can we somehow check for that error inside error handler besides it’s message content? There isn’t any error code for that, and instanceof check is not inituitive since errors modules is not exposed publicly.

This could also be related to comment in https://github.com/redis/node-redis/issues/1993#issuecomment-1079886754.

leibale commented 1 year ago

@niksy https://github.com/redis/node-redis#events

":warning: You MUST listen to error events. If a client doesn't have at least one error listener registered and an error occurs, that error will be thrown and the Node.js process will exit. See the EventEmitter docs for more details."

niksy commented 1 year ago

Yeah, I understand that, sorry I missed that part. It makes sense that this is needed, but it doesn’t answer the question why this type of error doesn’t happen on v3. I will see if it’s related to pinging you mentioned.