iframely icon indicating copy to clipboard operation
iframely copied to clipboard

iFramely 1.6.1 - no reconnect to Redis or blocking request

Open RSeidelsohn opened this issue 2 years ago • 4 comments

Hello,

we currently want to use iFramely 1.6.1 for our website, and it is configured to connect to a Redis server for faster responses for cached queries. Since we want to keep our website fast, we'd like to minimize the waiting time for situations in which our Redis might be unresponsive. I turns out, that - depending on the configuration for node-redis - either a request to iFramely will be waiting until iFramely can reconnect to Redis again (which can take a long time if Redis is down), or iFramely will stop trying to reconnect and then never reconnect again on it's own. For performance reasons, we would expect a behaviour that lets iFramely fall back to the normal service after a configured timeout, say 2 seconds, while in the background trying to re-establish the connection to Redis for a configurable amount of trials or time. Do we miss something, or does iFramely in fact behave like I described above?

Cheers, Roman.

RSeidelsohn avatar Mar 23 '22 08:03 RSeidelsohn

The reddis handler is in lib/cache-engines/redis.js. We don't use it in production, but you're welcome to review and do pull requests as required (it'll have to be against current develop branch, which is 2.0.x).

It may be better to post this change request to the node-redis project directly, so they add the options to their middleware.

Alternatively, you can also use redis-clustr as middleware in Iframely (CONFIG.REDIS_MODE === 'cluster'). This lib already has the reconnection options.

iparamonau avatar Mar 23 '22 12:03 iparamonau

Redis 4.x change the behaviour and has a lot of breaking changes. See you in https://github.com/redis/node-redis/blob/master/docs/v3-to-v4.md

I was fixed and adapted for 4.x:

Modify the content of lib/cache-engines/redis.js to:

    import log from '../../logging.js';
    import CONFIG from '../../config.loader.js';

    var client;

    if (CONFIG.REDIS_MODE === 'cluster') {
        const pkg = await import('redis-clustr');
        const RedisClustr = pkg.default;
        client = new RedisClustr(CONFIG.REDIS_CLUSTER_OPTIONS);
    } else {
        var pkg = await import('redis');
        client = pkg.createClient(CONFIG.REDIS_OPTIONS);
        await client.connect();
    }

    export async function set(key, data, options) {
        try {
            await client.multi()
            .set(key, JSON.stringify(data))
            .expire(key, options && options.ttl || CONFIG.CACHE_TTL)
            .exec()
        } catch (err) {
            log('   -- Redis set error ' + key + ' ' + err);
        }
    };

    export async function get(key, cb) {
        try {
            const data = await client.get(key);

            if (typeof data !== 'string') {
                return cb(null, data);
            }

            try {
                var parsedData = JSON.parse(data);
            } catch (ex) {
                return cb(ex);
            }

            cb(null, parsedData);

        } catch (err) {
            log('   -- Redis get error ' + key + ' ' + err);
            return cb(null, null);
        }
    };

Also in config.local.js file, REDIS_OPTIONS should set port and host settings under socket object, as you can see here: https://github.com/redis/node-redis/blob/master/docs/client-configuration.md

Maybe this can be used to a pull request

NormandoHall avatar May 18 '22 19:05 NormandoHall

Thanks. Please feel free to submit a PR. We'll be happy to check in.

iparamonau avatar May 18 '22 20:05 iparamonau

Thanks. Please feel free to submit a PR. We'll be happy to check in.

Done :+1:

NormandoHall avatar May 18 '22 21:05 NormandoHall

Closing this issue during housekeeping as the PR is now merged.

iparamonau avatar Oct 12 '23 12:10 iparamonau