简体   繁体   中英

NodeJS Redis - Reconnect In Background

The situation I have is - I am trying to retrieve a resource through REDIS key. If the key isn't present, then get it from an API.

Running into an issue where if the Redis connection dies or if I cannot connect to Redis from startup, then the nodejs library ('redis') will just continue to try to reconnect. And it is blocking me from getting the information I need through the API, as the retry logic will take over and will not continue on getting the needed information.

I would like this functionality running in the background - is it possible?

Meaning, if Redis is down/cannot connect to REDIS from NodeJs, then it will try to reconnect. However, while it is down and the app will try to periodically reconnect, I want to be able to get the data through the backup plan ie through the API, as I mentioned above.

Any pointers on this situation would be greatly appreciated - thank you in advance.

You could create a wrapper/proxy around your redis-connection where you make sure that redis is connected for all the redis operations. If not you can either throw an error (which you can handle in the caller) or return undefined.

Basically you can listen for the ready and error events and update a status -flag inside that wrapper in order to always know the current connection status.

Now, this will certainly cover the case when the initial connection is not successful or when a disconnect happens between calls. The problem are the rare cases where the disconnect happens after you checked the status -flag successfully. To tackle this you could define a max wait time for the redis call and return/throw an error if that timeout is reached and ignore the redis result. Here's some basic code which might help you get started:

class RedisService {
    isConnected = false;
    client;

    constructor() {
        this.client = redis.createClient();
        this.client.get = promisify(this.client.get).bind(this.client);
        this.client.set = promisify(this.client.set).bind(this.client);
        this.attachHandlers();
    }

    attachHandlers() {
        this.client.on("ready", () => {
            this.isConnected = true;
        });           
        this.client.on("error", (err) => {
            this.isConnected = false;
            console.log(err);
        });
    }

    async tryGet(key) {
        if (!this.isConnected) {
            return undefined; // or throw an error
        }
        return Promise.race([this.client.get(key), this.wait()]);
    }

    async trySet(key, val) {
        if (!this.isConnected) {
            return undefined; // or throw an error
        }
        return Promise.race([this.client.set(key, val), this.wait()]);
    }

    wait(ms = 200) {
        return new Promise(resolve => {
            setTimeout(resolve, ms);
        })
    }
}

Then in your caller you can do:

async someMethodThatCallsRedisOrApi() {
    let result;
    try {
        result = await redisService.tryGet('testkey');
    } catch (e) {
        console.log(e);
    }
    if (!result) {
        result = apiService.get(...); // call the actual api to get the result
        await redisService.trySet('testkey', result);
    }
    res.json(result)
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM