redis / node-redis

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

Cannot read properties of undefined (reading 'replicas') [calling "get"] #2704

Open danielbush opened 7 months ago

danielbush commented 7 months ago

Description

Environment:

We're getting this error - I think it's intermittent ie it works maybe even a lot of the time:

Stacktrace (redactions using xxx):

TypeError: Cannot read properties of undefined (reading 'replicas')
    at RedisClusterSlots.getSlotRandomNode (/server/node_modules/@redis/client/dist/lib/cluster/cluster-slots.js:118:19)
    at RedisClusterSlots.getClient (/server/node_modules/@redis/client/dist/lib/cluster/cluster-slots.js:110:37)
    at Commander._RedisCluster_execute (/server/node_modules/@redis/client/dist/lib/cluster/index.js:217:79)
    at Commander.sendCommand (/server/node_modules/@redis/client/dist/lib/cluster/index.js:129:98)
    at Commander.commandsExecutor (/server/node_modules/@redis/client/dist/lib/cluster/index.js:126:75)
    at BaseClass.<computed> [as get] (/server/node_modules/@redis/client/dist/lib/commander.js:8:29)
    at cacheItem (/server/node_modules/xxx:46:34)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async HttpClient.xxx (/server/node_modules/xxx:193:29)
    at async Promise.all (index 1)
    at async prefetchTask (/server/api/controllers/tasks.js:349:5)
    at async Promise.all (index 2)

You can see HttpClient (an internal library being asked to make a request. It then calls cacheItem (an internal module) which then calls redis.get as per code below to check if there's something in the cache using get before making the http request.

Code:

We get the client like this (within an async function). It is long-running, we keep using the same instance once created. Note we pass only one url to rootNodes - the cluster configuration endpoint provided by AWS Elasticache. (I wonder if that is an issue as the docs say to pass several nodes, I struggled to find docs on this).

    ...
    redisClient = redis.createCluster({
        // Assumes we are using AWS Elasticache cluster configuration endpoint
        // or similar.
        rootNodes: [{ url: config.url }],
        defaults: {
            // IMPORTANT: Simply not specifying `socket` here seems to
            // cause the client to hang regardless of what is in
            // `socket`.  An empty object suffices to make this go away.
            // It's mentioned here:
            // https://github.com/redis/node-redis/issues/1656#issuecomment-1212691760
            socket: {
                // If this is too small, we might get `Error: All the root nodes are unavailable`.
                connectTimeout: 5000,
                tls: true,
            },
        },
    });
    redisClient.on('error', error =>
        console.error(
            `getRedisClient: error occurred for ${config.url}`,
            error,
        ),
    );
    // Wait for it to connect to avoid any errors.
    await redisClient.connect();
    return redisClient;
    ...

Error is triggered in code like this using the above redisClient:

        const redis = await getRedisClient();
        try {
            cached = await redis.get(
                commandOptions({ returnBuffers: true }),
                key,
            );
        } catch (err) {
           ... log the error here ...

Node.js Version

18.19.1

Redis Server Version

6.2.6

Node Redis Version

4.6.13

Platform

Linux

Logs

No response

dstoyanoff commented 5 months ago

Hey guys, is there a workaround for this? I also faced that while trying to make redis work with ElastiCache Serverless

martinssonj commented 4 months ago

We also get a similar problem sometimes when using cluster mode against elasticache 7.1

TypeError: Cannot read properties of undefined (reading 'master')
    at RedisClusterSlots.getClient (/usr/src/app/node_modules/@redis/client/dist/lib/cluster/cluster-slots.js:108:59)
    at Commander._RedisCluster_execute (/usr/src/app/node_modules/@redis/client/dist/lib/cluster/index.js:217:79)
    at Commander.sendCommand (/usr/src/app/node_modules/@redis/client/dist/lib/cluster/index.js:129:98)
    at Commander.commandsExecutor (/usr/src/app/node_modules/@redis/client/dist/lib/cluster/index.js:126:75) 

Happens when we do many set commands in parallel.

MagnusHJensen commented 4 months ago

We are facing a similar issue, also pointing to a serverless elasticache 7.1.

Is it something that we can fix/help on our end?

danielbush commented 1 month ago

I tried redis 4.7 - I think it includes https://github.com/redis/node-redis/pull/2731 - but I'm still getting the original issue.

If anyone is seeing the contrary, let me know.

noor-siddique-paypay commented 1 month ago

rejectUnauthorized: false might be helpful

    redisClient = redis.createCluster({
        rootNodes: [{ url: config.url }],
        defaults: {
            socket: {
                tls: true,
                rejectUnauthorized: false
            },
        },
    });