Closed wyvasi closed 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!
We are currently stuck with v3 for months now because this issue seems to be still unresolved with v4.
@rpong Could you please update the tentative ETA for this issue as it is a blocker for v4?
@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..
Hey guys @leibale. Any updates on this fix for this issue?
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!
@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.
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.
client.on('error')
was required in v3 as well (see 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.
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!
@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
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.
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.
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?
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.
@ryanmeador can you please open a new issue with reproduction?
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 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.
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).
also you need to add listeners to publishers and subscribers
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
.
I'm facing the same issue. I use Redis version 6.0.
@flashtheman where is your redis server hosted? what version of node-redis are you using?
@leibale
Seeing the same on a managed redis db on digitalocean after upgrading.
Redis 6 node-redis: 4.5.1
@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)
Same issue here. Just installed, worked for a while and suddenly started conecting, disconncting and reconnecting without being able to do nothing.
I have the same issue in GKE : Redis: 7 node-redis: 4.5.1
@Nekidev @ahmedalmulki when this error occurs it's probably because:
CONFIG GET maxclients
, the server will close some clients. you can check that using INFO CLIENTS
.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.
@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 :)
@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.
@derikb you posted your comment before this comment, so maybe the problem you faced is already fixed?
@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.
@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 :)
@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
@derikb
CLIENT KILL
commandI guess there are more ways, but these are the ones I currently have in mind...
@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?
@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)
@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
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?
@HenonoaH try to add listeners to all available events like ready reconnect error etc.
@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.
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 {}
@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.
@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();
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.
@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."
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.
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).
Here is where I catch the parser error: client/socket.ts
List with buffers and offsets:
Code for creating the client
Environment: