Reusing Redis Connection: Socket Closed Unexpectedly - node-redis
Asked Answered
P

6

13

First, let me tell you how I'm using Redis connection in my NodeJS application:

  • I'm re-using one connection throughout the app using a singleton class.
class RDB {

    static async getClient() {
        if (this.client) {
            return this.client
        }

        let startTime = Date.now();

        this.client = createClient({
            url: config.redis.uri
        });

        await this.client.connect();

        return this.client;
    }

}

For some reason - that I don't know - time to time my application crashes giving an error without any reason - this happens about once or twice a week:

Error: Socket closed unexpectedly

Now, my questions:

  1. Is using Redis connections like this alright? Is there something wrong with my approach?
  2. Why does this happen? Why is my socket closing unexpectedly?
  3. Is there a way to catch this error (using my approach) or any other good practice for implementing Redis connections?
Platy answered 22/3, 2022 at 15:34 Comment(0)
P
11

I solved this using the 'error' listener. Just listening to it - saves the node application from crashing.

client.on("error", function(error) {
   console.error(error);
   // I report it onto a logging service like Sentry. 
});
Platy answered 16/6, 2022 at 7:49 Comment(3)
Does the error say why its crashing?Heyduck
Probably a timeout from an unused socket.Burtis
Does the client reconnect automatically?Armour
S
6

I had similar issue of socket close unexpectedly. The issue started while I upgraded node-redis from 3.x to 4.x. The issue was gone after I upgraded my redis-server from 5.x to 6.x.

Scalf answered 21/4, 2022 at 14:31 Comment(0)
Z
4

I got the same issue (Socket Closed Unexpectedly) but only with the remote Redis servers, so I figured out that maybe there is a problem with the TLS. So I tried to use redis:// instead of rediss://, and yes it was working stable.

Zoraidazorana answered 4/1 at 10:31 Comment(0)
U
3

You should declare a private static member 'client' of the RDB class, like this:

private static client;

In a static method, you can't reference instance of 'this', you need to reference the static class member like this:

RDB.client

And it would be better to check, whether the client's connection is open, rather than simply checking if the client exists (considering you are using the 'redis' npm library). Like this:

if (RDB.client && RDB.client.isOpen)

After the changes, your code should look like this:

class RDB {
    private static client;

    static async getClient() {
        if (RDB.client && RDB.client.isOpen) {
            return RDB.client;
        }

        RDB.client = createClient({
            url: config.redis.uri
        });

        await RDB.client.connect();

        return RDB.client;
    }
}

Note: the connect() method and isOpen property only exist in redis version ^4.0.0.

Unman answered 23/3, 2022 at 12:37 Comment(0)
P
0

I switched to ioredis with the same configuration and this issue is gone.

Parkland answered 2/2 at 16:5 Comment(0)
T
0

There is option pingInterval you can pass to createClient function to keep socket alive. Ping server every 3 seconds.

export const redis = createClient({
    url: 'redis://localhost:6379',
    pingInterval: 3000,
});
Taft answered 13/5 at 6:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.