Establish 'connection retry' behaviour on start-up even when Redis is not available
Asked Answered
H

4

7

node-redis has fantastic functionality for handling any Redis disconnections once everything is up and running. If the Redis instance becomes unavailable, use of an appropriate retry_strategy means the client can be set up to try to reconnect until Redis is available again.

Is it possible to get the client to enter this state at start-up, even if Redis is down?

My scenario is this: I am using Redis as a primary data-store, with a fallback secondary data-store which is not Redis-based. When my application starts, if Redis is not available, attempts to retrieve data will use the secondary data-store instead.

However, when Redis does become available, I'd like my application to start using the Redis primary data-store instead. As the Redis connection did not succeed on start-up, the retry_strategy, which would handle this for a previously established connection, does not work.

I could write code which will retry the initial Redis connection until it is successful, but it strikes me that the functionality available out-of-the-box is already very close to what I need, if I can persuade it to come into play from start-up even though Redis is down.

Hesione answered 23/8, 2017 at 10:13 Comment(0)
D
7

By default a client will try reconnecting until connected. You can use the retry_strategy available in the options object properties if you want to customise it. you can know when the redis is connected since it would emit an event

client.on("connect", function (){
});

you can later decide how to handle once connected

Disembark answered 23/8, 2017 at 10:28 Comment(3)
But will it try reconnecting like this even if Redis is not available from start-up?Hesione
it does say in their docs that it would keep trying to reconnect, you can test this by listening to the reconnect event mention in github.com/NodeRedis/node_redis#reconnectingDisembark
try connecting to an offline server and listen to the reconnecting event to verifyDisembark
B
15

The retry_strategy can actually return a number in milliseconds to attempt to retry the connection after that time. If the connection is closed when your node starts up, you can simply return e.g. 5000 when the error code is NR_CLOSED or ECONNREFUSED to have it retry after 5 seconds.

Example:

const retry_strategy = function(options) {
    if (options.error && (options.error.code === 'ECONNREFUSED' || options.error.code === 'NR_CLOSED')) {
        // Try reconnecting after 5 seconds
        console.error('The server refused the connection. Retrying connection...');
        return 5000;
    }
    if (options.total_retry_time > 1000 * 60 * 60) {
        // End reconnecting after a specific timeout and flush all commands with an individual error
        return new Error('Retry time exhausted');
    }
    if (options.attempt > 50) {
        // End reconnecting with built in error
        return undefined;
    }
    // reconnect after
    return Math.min(options.attempt * 100, 3000);
}

And create the client with this retry strategy:

const client = redis.createClient({retry_strategy: retry_strategy});
Boyer answered 22/3, 2018 at 2:15 Comment(0)
D
7

By default a client will try reconnecting until connected. You can use the retry_strategy available in the options object properties if you want to customise it. you can know when the redis is connected since it would emit an event

client.on("connect", function (){
});

you can later decide how to handle once connected

Disembark answered 23/8, 2017 at 10:28 Comment(3)
But will it try reconnecting like this even if Redis is not available from start-up?Hesione
it does say in their docs that it would keep trying to reconnect, you can test this by listening to the reconnect event mention in github.com/NodeRedis/node_redis#reconnectingDisembark
try connecting to an offline server and listen to the reconnecting event to verifyDisembark
U
2

Using the reconnectStrategy inside the socket section in client options. In the below example using Exponential backoff

 const maxConnectRetry = 10
 const minConnectDelay = 100; // Milliseconds
 const maxConnectDelay = 60000; // Milliseconds
 
 const client = redisObj.createClient({
    socket: {
        host: host,
        port: port,
        connectTimeout: 5000,
        reconnectStrategy: (retries) => {
            if (retries > maxConnectRetry) {
                console.log("Too many retries on REDIS. Connection Terminated");
                return new Error("Too many retries.");
            } else {
                const wait = Math.min(minConnectDelay * Math.pow(2, retries), maxConnectDelay);
                console.log("waiting", wait, "milliseconds");
                return wait;
            }
        }
    },
    database: dbIndex
});
Uhland answered 17/4, 2023 at 8:29 Comment(0)
C
0

As per v4 documentation, we can utilize the socket.reconnectStrategy and client.on("error") event.

// redisClient.js
const redis = require('redis');

const maxRetries = 100; // Number of times to try for reconnecting
const retryDelay = 10000; // Milliseconds

const redisConfig = {
  url: `redis://default:${password}@${host}:6379`,
  socket: {
    reconnectStrategy: (retries) => {
      if (retries > maxRetries) {
        return undefined; // Connection terminates
      }
      console.log(`Retrying redis connection - ${retries}`);
      return retryDelay;
    },
  },
};

const redisClient = redis.createClient(redisConfig);
let isConnectionSuccess = false;

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

redisClient.on('error', async (e) => {
  isConnectionSuccess = false;
  console.log('Redis error: ', JSON.stringify(e, null, 2));
});

redisClient.connect();

const isClientAvailable = () => {
  return isConnectionSuccess;
};

module.exports = { redisClient, isClientAvailable };

You can check if isClientAvailable() and then return null.

// cache.js
const { redisClient, isClientAvailable } = require('./redisClient');

const getKey = async (key) => {
  if (!isClientAvailable()) return null;
  const data = await redisClient.get(key);
  return JSON.parse(data);
};

Here, the server will try to connect to the redis-server if available. Otherwise, it will fallback to the secondary data store.

on.("error") event retries to connect to redis-server again and again in the given delay(retryDelay) until maxRetries exceeds.

Corriecorriedale answered 16/11, 2023 at 6:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.