Node-redis: рддреНрд░реБрдЯрд┐, рдЬреЛ retry_strategy рд╕реЗ рд╡рд╛рдкрд╕ рдЖрддреА рд╣реИ, рдзреНрдпрд╛рди рдореЗрдВ рдирд╣реАрдВ рд░рд╣рддреА рд╣реИ

рдХреЛ рдирд┐рд░реНрдорд┐рдд 27 рдлрд╝рд░ре░ 2017  ┬╖  19рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ  ┬╖  рд╕реНрд░реЛрдд: NodeRedis/node-redis

рдореЗрд░реЗ рдкрд╛рд╕ рдиреАрдЪреЗ рджрд┐рдпрд╛ рдЧрдпрд╛ рдХреЛрдб рд╣реИ рдФрд░ iptables -A OUTPUT -p tcp --dport 6379 -j REJECT рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЧрд┐рд░рд╛рдП рдЧрдП рдХрдиреЗрдХреНрд╢рди рдХреА рдирдХрд▓ рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░реЗрдВред

self.client = redis.createClient(self.cfg.port, self.cfg.host, {
    retry_strategy: function (options) {
        console.log('retry strategy check');
        console.log(options);
        if (options.error) {
            if (options.error.code === 'ECONNREFUSED') {
                // End reconnecting on a specific error and flush all commands with a individual error
                return new Error('The server refused the connection');
            }
            if (options.error.code === 'ECONNRESET') {
                return new Error('The server reset the connection');
            }
            if (options.error.code === 'ETIMEDOUT') {
                return new Error('The server timeouted the connection');
            }
        }
        if (options.total_retry_time > 1000 * 60 * 60) {
            // End reconnecting after a specific timeout and flush all commands with a individual error
            return new Error('Retry time exhausted');
        }
        if (options.attempt > 5) {
            // End reconnecting with built in error
            return new Error('Retry attempts ended');
        }
        // reconnect after
        return 1000;
    }
});
self.client.on('ready', function () {
    log.trace('Redis client: ready');
});
self.client.on('connect', function () {
    log.trace('Redis client: connect');
});
self.client.on('reconnecting', function () {
    log.trace('Redis client: reconnecting');
});
self.client.on('error', function (err) {
    log.error({err: err}, 'Listener.redis.client error: %s', err);
    process.exit(1);
});
self.client.on('end', function () {
    log.trace('Redis client: end');
});
self.client.on('warning', function () {
    log.trace('Redis client: warning');
});

рдпрд╣ рдорд╛рдирд╛ рдЬрд╛рддрд╛ рд╣реИ рдХрд┐ рддреНрд░реБрдЯрд┐ рдШрдЯрдирд╛ рдореЗрдВ рд╕рднреА рд░реЗрдбрд┐рд╕ рддреНрд░реБрдЯрд┐рдпрд╛рдВ рдЙрддреНрд╕рд░реНрдЬрд┐рдд рд╣реЛрддреА рд╣реИрдВред рд▓реЗрдХрд┐рди рдпрд╣рд╛рдБ рдореБрдЭреЗ рдХрдВрд╕реЛрд▓ рдЖрдЙрдЯрдкреБрдЯ рдореЗрдВ рдорд┐рд▓рд╛ рд╣реИ:

21:00:14.666рдЬреЗрдб рдЯреНрд░реЗрд╕ рд╕реНрдХреНрд░рд┐рдкреНрдЯ: рд░реЗрдбрд┐рд╕ рдХреНрд▓рд╛рдЗрдВрдЯ: рдХрдиреЗрдХреНрдЯ
21:00:14.695рдЬреЗрдб рдЯреНрд░реЗрд╕ рд╕реНрдХреНрд░рд┐рдкреНрдЯ: рд░реЗрдбрд┐рд╕ рдХреНрд▓рд╛рдЗрдВрдЯ: рддреИрдпрд╛рд░
21:10:23.837Z рдЯреНрд░реЗрд╕ рд╕реНрдХреНрд░рд┐рдкреНрдЯ: рд░реЗрдбрд┐рд╕ рдХреНрд▓рд╛рдЗрдВрдЯ: рдПрдВрдб
рдкреБрди: рдкреНрд░рдпрд╛рд╕ рд░рдгрдиреАрддрд┐ рдЬрд╛рдВрдЪ
{рдкреНрд░рдпрд╛рд╕: 1,
рддреНрд░реБрдЯрд┐: { [рддреНрд░реБрдЯрд┐: redis.callision рдХреЗ рд▓рд┐рдП Redis рдХрдиреЗрдХреНрд╢рдиред рдЬрд╛рдирдХрд╛рд░реА: 6379 рд╡рд┐рдлрд▓ - ECONNRESET рдкрдврд╝реЗрдВ] рдХреЛрдб: 'ECONNRESET', рддреНрд░реБрдЯрд┐: 'ECONNRESET', syscall: 'рдкрдврд╝реЗрдВ'},
Total_retry_time: 0,
рдЯрд╛рдЗрдореНрд╕_рдХрдиреЗрдХреНрдЯреЗрдб: 1 }

/рдиреЛрдб_рдореЙрдбреНрдпреВрд▓/рдХреНрдпреВ/рдХреНрдпреВ.рдЬреЗрдПрд╕:155
рдлреЗрдВрдХ рдИ;
^
AbortError: рд╕реНрдЯреНрд░реАрдо рдХрдиреЗрдХреНрд╢рди рд╕рдорд╛рдкреНрдд рд╣реЛ рдЧрдпрд╛ рдФрд░ рдЖрджреЗрд╢ рдирд┐рд░рд╕реНрдд рдХрд░ рджрд┐рдпрд╛ рдЧрдпрд╛ред рд╣реЛ рд╕рдХрддрд╛ рд╣реИ рдХрд┐ рдЗрд╕реЗ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реЛред
RedisClient.flush_and_error (/node_modules/redis/index.js:350:23) рдкрд░
RedisClient.connection_gone рдкрд░ (/node_modules/redis/index.js:612:18)
RedisClient.on_error рдкрд░ (/node_modules/redis/index.js:398:10)
рд╕реЙрдХреЗрдЯ рдкрд░ред(/node_modules/redis/index.js:272:14)
рдПрдорд┐рдЯрд╡рди рдкрд░ (events.js:90:13)
Socket.emit рдкрд░ (events.js:182:7)
рдкрд░ emitErrorNT (net.js:1255:8)
nextTickCallbackWith2Args рдкрд░ (рдиреЛрдб.рдЬреЗрдПрд╕:474:9)
рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдкрд░._рдЯрд┐рдХ рдХреЙрд▓рдмреИрдХ (рдиреЛрдб.рдЬреЗрдПрд╕:388:17)

рдФрд░ рдПрдХ рдкреНрд░рд╢реНрди рдХреЗ рд░реВрдк рдореЗрдВ: рдпрд╣ рдкрддрд╛ рд▓рдЧрд╛рдиреЗ рдореЗрдВ рд▓рдЧрднрдЧ 10 рдорд┐рдирдЯ рдХреНрдпреЛрдВ рд▓рдЧрддреЗ рд╣реИрдВ рдХрд┐ рдХрдиреЗрдХреНрд╢рди рдЪрд▓рд╛ рдЧрдпрд╛ рд╣реИ? рдХреНрдпрд╛ 10 рд╕реЗрдХрдВрдб рдХреЗ рднреАрддрд░ рдХреЛрдИ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдирд╣реАрдВ рд╣реЛрдиреЗ рдХреА рд╕реНрдерд┐рддрд┐ рдореЗрдВ рддреНрд░реБрдЯрд┐ рдЙрддреНрдкрдиреНрди рдХрд░рдиреЗ рдХрд╛ рдХреЛрдИ рддрд░реАрдХрд╛ рд╣реИ? рдХреЛрдИ рднреА рд╡рд┐рдХрд▓реНрдк рд╣реЛ рд╕рдХрддрд╛ рд╣реИ рдЬреИрд╕реЗ response_timeout рдЖрджрд┐ред

  • рд╕рдВрд╕реНрдХрд░рдг : рдиреЛрдб_рд░реЗрдбрд┐рд╕ v.2.6.5 рдФрд░ рд░реЗрдбрд┐рд╕ 3.0.7
  • рдкреНрд▓реЗрдЯрдлрд╛рд░реНрдо : Node.js v5.5.0 Ubuntu 14.04.4 LTS рдкрд░
  • рд╡рд┐рд╡рд░рдг : retry_strategy рд╕реЗ рддреНрд░реБрдЯрд┐ рдЕрднреА рднреА рдзреНрдпрд╛рди рдореЗрдВ рдирд╣реАрдВ рд╣реИ
pending-author-input

рд╕рдмрд╕реЗ рдЙрдкрдпреЛрдЧреА рдЯрд┐рдкреНрдкрдгреА

рдХреЛрдИ рдЦрдмрд░ ? рдореЗрд░реА рднреА рдпрд╣реА рд╕рдорд╕реНрдпрд╛ рд╣реИред

рд╕рднреА 19 рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

@pavelsc рдореИрдВрдиреЗ рдЗрд╕реЗ рдкреБрди: рдкреЗрд╢ рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХреА рд▓реЗрдХрд┐рди рдЕрднреА рддрдХ рдореИрдВ рдирд╣реАрдВ рдХрд░ рд╕рдХрд╛ред

рдХреГрдкрдпрд╛ рдХрд┐рд╕реА рддреАрд╕рд░реЗ рдкрдХреНрд╖ рдХреЗ рдореЙрдбреНрдпреВрд▓ рдХреЗ рдмрд┐рдирд╛ рдЗрд╕ рдореБрджреНрджреЗ рдХреЛ рдкреБрди: рдкреЗрд╢ рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░реЗрдВред рд╡рд░реНрддрдорд╛рди рдореЗрдВ рдЖрдк рдХрдо рд╕реЗ рдХрдо q рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рдкреНрд░рддреАрдд рд╣реЛрддреЗ рд╣реИрдВред

рдореБрдЭреЗ рдПрдХ рд╣реА рддреНрд░реБрдЯрд┐ рдХрд╛ рд╕рд╛рдордирд╛ рдХрд░рдирд╛ рдкрдбрд╝ рд░рд╣рд╛ рд╣реИред рдЕрдЧрд░ рдореИрдВ рдЬрд╛рдирдмреВрдЭрдХрд░ рд░реЗрдбрд┐рд╕ рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЛ рдПрдХ рдЦрд░рд╛рдм рдпреВрдЖрд░рдПрд▓ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реВрдВ, рддреЛ on.error рд╡рд┐рдзрд┐ рд▓рд╛рдЧреВ рдирд╣реАрдВ рд╣реЛрддреА рд╣реИред рдпреЗ рд░рд╣рд╛ рдПрдХ рд╕рд░рд▓ рдЙрджрд╛рд╣рд░рдг:

var redis = require("redis");

exports.handler = function (event, context, callback) {

    console.log("Executing test lambda for diagnosing redis issues");

    var redisInfo = {
        HOST: process.env.REDIS_HOST,
        PORT: process.env.REDIS_PORT
    };

    console.log(process.env.REDIS_HOST);
    console.log(process.env.REDIS_PORT);

    console.log("Connecting to Redis...");

    var client = redis.createClient({
        host: redisInfo.HOST,
        port: redisInfo.PORT,
        retry_strategy: function (options) {

            if (options.total_retry_time > 2000) {
                console.log("throwing an error...");
                return new Error('Retry time exhausted');
            }

            return 200;
        }
    });

    // if you'd like to select database 3, instead of 0 (default), call
    // client.select(3, function() { /* ... */ });

    client.on("error", function (err) {
        console.log("Error " + err);
        callback(null, "Error with Redis");
    });

    client.on('connect', function() {
        console.log("Connected to Redis");
    });

    client.on('end', function() {
        console.log("Redis end");
    });

    client.set("string key", "string val", redis.print);
    client.hset("hash key", "hashtest 1", "some value", redis.print);
    client.hset(["hash key", "hashtest 2", "some other value"], redis.print);
    client.hkeys("hash key", function (err, replies) {
        console.log(replies.length + " replies:");
        replies.forEach(function (reply, i) {
            console.log("    " + i + ": " + reply);
        });
        client.quit();
    });

    client.quit();

    callback(null, "Success");
};

рдЕрднреА рдХреЗ рд▓рд┐рдП рдореИрдВ connect_timeout рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╡рд╛рдкрд╕ рд▓реМрдЯ рд░рд╣рд╛ рд╣реВрдВ, рдЬреЛ рдХрдиреЗрдХреНрдЯ рдЯрд╛рдЗрдордЖрдЙрдЯ рд╕рдорд╛рдкреНрдд рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж рд╕рд╣реА рдврдВрдЧ рд╕реЗ 'рддреНрд░реБрдЯрд┐' рдкрд░ рдирд┐рдХрд▓рддрд╛ рд╣реИред

рдореЗрд░реЗ рдкрд╛рд╕ рдПрдХ рд╣реА рд╕рдорд╕реНрдпрд╛ рд╣реИ, рдПрдХ рдЦрд░рд╛рдм рдПрдВрдбрдкреЙрдЗрдВрдЯ рдХреЗ рд╕рд╛рде рдПрдХ рдХрд╕реНрдЯрдо retry_strategy рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ "AbortError:" рдореЗрдВ рд╕рдорд╛рдкреНрдд рд╣реЛрддрд╛ рд╣реИ

рдЗрд╕рдиреЗ рдореБрдЭреЗ рдЖрдЬ рднреА рдкрдХрдбрд╝ рд▓рд┐рдпрд╛ред рдХреЛрдб рдХреЛ рд╕рдВрдХреНрд╖реЗрдк рдореЗрдВ рджреЗрдЦрдиреЗ рд╕реЗ, рдпрд╣ рдЬрд╛рдирдмреВрдЭрдХрд░ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╡реНрдпрд╡рд╣рд╛рд░ рдкреНрд░рддреАрдд рд╣реЛрддрд╛ рд╣реИред https://github.com/NodeRedis/node_redis/blob/79558c524ff783000a6027fb159739770f98b10e/index.js#L405 рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рдмрддрд╛рддрд╛ рд╣реИ рдХрд┐ рдпрджрд┐ retry_strategy рд╕реЗрдЯ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рддреЛ рддреНрд░реБрдЯрд┐ рдХрд╛ рдЙрддреНрд╕рд░реНрдЬрди рди рдХрд░реЗрдВ рдФрд░ рдЗрд╕рдХреЗ рдмрдЬрд╛рдп рдЗрд╕реЗ рдлреЗрдВрдХрдирд╛ рдЬрд╛рд░реА рд░рдЦреЗрдВред рдореБрдЭреЗ рдпрд╣ рдЬрд╛рдирдиреЗ рдХреА рдЙрддреНрд╕реБрдХрддрд╛ рд╣реЛрдЧреА рдХрд┐ рдРрд╕рд╛ рдХреНрдпреЛрдВ рд╣реИ, рд╣рд╛рд▓рд╛рдВрдХрд┐ рдРрд╕рд╛ рдХреЛрдИ рдХрд╛рд░рдг рдирд╣реАрдВ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдПрдХ рддреНрд╡рд░рд┐рдд рдирдЬрд╝рд░ рд╕реЗ рдлреЗрдВрдХрдиреЗ рдХреЗ рдмрдЬрд╛рдп рдЗрд╕реЗ рдЙрддреНрд╕рд░реНрдЬрд┐рдд рдирд╣реАрдВ рдХрд░ рд╕рдХрддрд╛ рд╣реИред рдХреНрдпрд╛ рдХреЛрдИ рдХрд╛рд░рдг рд╣реИ рдХрд┐ рдпрд╣ рд╕рд╢рд░реНрдд рдирд╣реАрдВ рдирд┐рдХрд╛рд▓рд╛ рдЬрд╛ рд╕рдХрд╛, рддрд╛рдХрд┐ рддреНрд░реБрдЯрд┐ рд╣рдореЗрд╢рд╛ рдЙрддреНрд╕рд░реНрдЬрд┐рдд рд╣реЛ?

рдореБрдЭреЗ рднреА рдпрд╣ рд╕рдорд╕реНрдпрд╛ рд▓рдЧрд╛рддрд╛рд░ рд╣реЛ рд░рд╣реА рд╣реИред

рдореИрдВ рднреА ENOTFOUND рдкреНрд░рд╛рдкреНрдд рдХрд░рддреЗ рд╕рдордп рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЛ рдкрдХрдбрд╝рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рдирд╣реАрдВ рд╣реВрдВред

{
    host: "foo",
    retry_strategy: function (options) {
        if (options.error && options.error.code === "ENOTFOUND") {
            return new Error("The server was not found");
        }

        // reconnect after
        return 1000;
}

рд╕рд╛рде:

redis.on("error", err => {
    console.error("Cache Error: " + err);
});

рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рдбреАрдмрдЧ рдХрд░рдирд╛, рдореИрдВ ENOTFOUND рдЪреЗрдХ рдореЗрдВ рд╢рд╛рдорд┐рд▓ рд╣реЛ рд░рд╣рд╛ рд╣реВрдВ рдЬреИрд╕рд╛ рдХрд┐ retry_strategy рдореЗрдВ рдКрдкрд░ рдмрддрд╛рдпрд╛ рдЧрдпрд╛ рд╣реИ рд▓реЗрдХрд┐рди рдпрд╣ рддреНрд░реБрдЯрд┐ рдИрд╡реЗрдВрдЯ рд╣реИрдВрдбрд▓рд░ рдХрд╛ рдЖрд╣реНрд╡рд╛рди рдирд╣реАрдВ рдХрд░ рд░рд╣рд╛ рд╣реИред

рдореЗрд░реЗ рдкрд╛рд╕ рдПрдХ рд╣реА рд╕рдорд╕реНрдпрд╛ рд╣реИ, рд╕реНрд░реЛрдд рдХреЛрдб рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЦреБрджрд╛рдИ рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж рдореИрдВрдиреЗ рдкрд╛рдпрд╛ рдХрд┐ рдЕрдЧрд░ рд╣рдо рдмрджрд▓рддреЗ рд╣реИрдВ
рдпрд╣ рд▓рд╛рдЗрди (рдпрд╛ рдбреАрдмрдЧ рдореЛрдб рд╕рдХреНрд╖рдо рдХрд░реЗрдВ)
https://github.com/NodeRedis/node_redis/blob/009479537eb920d2c34045026a55d31febd1edd7/index.js#L381 -L382

рдФрд░ рдХреЛрдб рдХрд╛ рдпрд╣ рдЯреБрдХрдбрд╝рд╛ рдпрд╣рд╛рдВ рдбрд╛рд▓реЗрдВ (рд╕рд░рдгреА рдореЗрдВ рддреБрд░рдВрдд рддреНрд░реБрдЯрд┐ рдЬреЛрдбрд╝реЗрдВ)
https://github.com/NodeRedis/node_redis/blob/009479537eb920d2c34045026a55d31febd1edd7/index.js#L352 -L353

    if (options.error) {
      aggregated_errors.push(options.error);
    }

рдпрд╣ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ рдФрд░ 'рддреНрд░реБрдЯрд┐' рдХреЛ рд╕рд╣реА рдврдВрдЧ рд╕реЗ рдЙрддреНрд╕рд░реНрдЬрд┐рдд рдХрд░рддрд╛ рд╣реИред

рдЙрд╕ рдлрд╝рдВрдХреНрд╢рди рдореЗрдВ рдиреЗрд╕реНрдЯреЗрдб рд▓реВрдк рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдирд╣реАрдВ рд╣реЛрддрд╛ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ 'command_queue' рдЦрд╛рд▓реА рд╣реИ рдФрд░ рддреНрд░реБрдЯрд┐ рдХрднреА рднреА рд╕рд░рдгреА рдореЗрдВ рдирд╣реАрдВ рдЬреБрдбрд╝рддреА рд╣реИ рдФрд░ рдЗрд╕ рдкреНрд░рдХрд╛рд░ рдЙрддреНрд╕рд░реНрдЬрд┐рдд рдирд╣реАрдВ рд╣реЛрддреА рд╣реИред рдЕрдЧрд░ рдореИрдВ рд╕рд╣реА рдврдВрдЧ рд╕реЗ рд╕рдордЭреВрдВ , рддреЛ рдпрд╣ рдХрд╛рдлреА рдкреБрд░рд╛рдирд╛ рдХреЛрдб рд╣реИ, рдЗрд╕рд▓рд┐рдП рд╣рдореЗрдВ рдЕрдиреБрд░рдХреНрд╖рдХреЛрдВ рд╕реЗ рдпрд╛

рдореИрдВрдиреЗ рдпрд╣ рднреА рджреЗрдЦрд╛ рдХрд┐ рдкрд╣рд▓реЗ рдЕрд╕рдлрд▓ рдХрдиреЗрдХреНрд╢рди рдкрд░ 'рдЕрдВрдд' рдШрдЯрдирд╛ рдХрд╛ рдЙрддреНрд╕рд░реНрдЬрди рд╣реЛрддрд╛ рд╣реИ, рдЗрд╕рдХрд╛ рдорддрд▓рдм рдХреБрдЫ (рдпрд╛ рдирд╣реАрдВ) рд╣реЛ рд╕рдХрддрд╛ рд╣реИ, рдореИрдВрдиреЗ рджреЛ рджрд┐рди рдкрд╣рд▓реЗ рд░реЗрдбрд┐рд╕ рдХреЛ рдЙрдард╛рдпрд╛ рдерд╛, рдЗрд╕рд▓рд┐рдП рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдирд╣реАрдВ рд╣реИ рдХрд┐ рдЖрдВрддрд░рд┐рдХ рдЕрднреА рддрдХ рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рддреЗ рд╣реИрдВред рдЬрдм рдореЗрд░реЗ рдкрд╛рд╕ рд╕рдордп рд╣реЛрдЧрд╛ рддреЛ рдореИрдВ рдереЛрдбрд╝рд╛ рдФрд░ рдХрд╛рдВрдЯрд╛ рдФрд░ рдЦреБрджрд╛рдИ рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░реВрдВрдЧрд╛ред

рдФрд░ рд╕рдЪрдореБрдЪ рдЕрдЧрд▓рд╛ рдЕрдВрдХ рдЗрд╕ рд╕рдорд╕реНрдпрд╛ рд╕реЗ рдЬреБрдбрд╝рд╛ рд╣реБрдЖ рд▓рдЧрддрд╛ рд╣реИ #1198

@ v1adko рдореИрдВ рд╡рд░реНрддрдорд╛рди рдореЗрдВ рдпрд╛рддреНрд░рд╛ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ, рд▓реЗрдХрд┐рди рдореИрдВ рдЗрд╕реЗ рдЖрдЬ рдпрд╛ рдХрд▓ рдмрд╛рдж рдореЗрдВ рджреЗрдЦрдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░реВрдВрдЧрд╛ (рдЬрдм рддрдХ рдХрд┐ рд░реВрдмреЗрди рдореБрдЭреЗ рдЗрд╕рдореЗрдВ рдирд╣реАрдВ рдорд╛рд░рддрд╛)ред

рддреНрд░реБрдЯрд┐ рдкрд░рд┐рджреГрд╢реНрдпреЛрдВ рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдореЗрд░реЗ рдкрд╛рд╕ рдореЗрд░рд╛ рд░реЗрдбрд┐рд╕ рдпреВрдЖрд░рдПрд▓ рдЬрд╛рдирдмреВрдЭрдХрд░ рдЧрд▓рдд рд╣реИ, рд▓реЗрдХрд┐рди рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рд░реЗрдбрд┐рд╕ рд╕реЗ рдХрдиреЗрдХреНрдЯ рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░рддреЗ рд╕рдордп рдореЗрд░реА retry_strategy рдХреЛ рд▓рд╛рдЧреВ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред рдХрдиреЗрдХреНрд╢рди рдмрдВрдж рд╣реЛрдиреЗ рдкрд░ рд╣реА retry_strategy рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред

`рдХреЙрдиреНрд╕реНрдЯ рд░реЗрдбрд┐рд╕ = рдЖрд╡рд╢реНрдпрдХрддрд╛ ('рд░реЗрдбрд┐рд╕');
рдХреЙрдиреНрд╕реНрдЯ рд▓реЙрдЧ = рдЖрд╡рд╢реНрдпрдХрддрд╛ ('./logUtil')ред рд▓рдХрдбрд╝рд╣рд╛рд░рд╛;

рдореЙрдбреНрдпреВрд▓.рдПрдХреНрд╕рдкреЛрд░реНрдЯреНрд╕.рдХрдиреЗрдХреНрдЯ = () => {

var redisRetryStrategy = function(options) {
    if (options.error && options.error.code === 'ECONNREFUSED') {
        // End reconnecting on a specific error and flush all commands with 
        // a individual error
        log.error('The redis server refused the connection');
        return new Error('The redis server refused the connection');
    }

    log.info(`Already spent ${options.total_retry_time} milliseconds to re-establish connection with redis`);
    if (options.total_retry_time > 2000) {
        // End reconnecting after a specific timeout and flush all commands 
        // with a individual error 
        log.error('Retry time exhausted');
        return new Error('Retry time exhausted');
    }
    log.info(`Attempting ${options.attempt} time to establish connection with redis`);
    if (options.attempt > 5) {
        // End reconnecting with built in error 
        log.error('Exhausted the retry attempts to establish connection to redis');
        return undefined;
    }
    // reconnect after 
    return 100;
}


log.info(`Redis connection url is :${process.env.REDIS_URL}`);
var redisClient = redis.createClient(qualifyUrl(process.env.REDIS_URL), {
    retry_strategy: redisRetryStrategy
});

redisClient.offline_queue_length = 3;

redisClient.on('connect', function() {
    console.log('Connected to Redis');
});

redisClient.on('reconnecting', function() {
    console.log('Re-Connecting to Redis');
});

redisClient.on('error', (err)=> {
    console.log(`Error trying to create redis connection: ${JSON.stringify(err)}`);
});
return redisClient;

}

рдХреЙрдиреНрд╕ рдХреНрд╡рд╛рд▓рд┐рдлрд╛рдИрдпреВрдЖрд░рдПрд▓ = (рдпреВрдЖрд░рдПрд▓) => {
рд╡рд╛рдкрд╕реА '//' + url.replace(/^\/+/,"");
};

`

рдХреНрдпрд╛ рдХреЛрдИ рдЗрд╕ рдореБрджреНрджреЗ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдореЗрдВ рдореЗрд░реА рдорджрдж рдХрд░ рд╕рдХрддрд╛ рд╣реИред

рдореЗрд░рд╛ рднреА рдпрд╣реА рд╡рд┐рдЪрд╛рд░ рд╣реИред рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдмреБрд░рд╛ рд╣реИрдХ рдЕрдкреЗрдХреНрд╖рд┐рдд рд╡реНрдпрд╡рд╣рд╛рд░ рдмрдирд╛рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдирд╣реАрдВ рд╣реИ рдХрд┐ рдЗрд╕рдХрд╛ рдХреЛрдИ рд╡реНрдпрд╛рдкрдХ рдкреНрд░рднрд╛рд╡ рд╣реИ рдпрд╛ рдирд╣реАрдВ:

const client = redis.createClient({
  retry_strategy: ({error}) => client.emit('error', error)
});

client.on('error', console.error);

рдореБрдЭреЗ рдЗрд╕ рд╕рдордп рд╡рд╣реА рд╕рдорд╕реНрдпрд╛рдПрдВ рдЖ рд░рд╣реА рд╣реИрдВред Retry_strategy рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ, рд░реАрдбрдореА рдореЗрдВ рдЙрджрд╛рд╣рд░рдг рдХреЗ рдЕрдиреБрд╕рд╛рд░ рддреНрд░реБрдЯрд┐ рдХреЛ рд╡рд╛рдкрд╕ рдХрд░рдирд╛, рдлрд┐рд░ рднреА рдХреНрд▓рд╛рдЗрдВрдЯ рджреНрд╡рд╛рд░рд╛ рдХреЛрдИ рддреНрд░реБрдЯрд┐ рдЙрддреНрд╕рд░реНрдЬрд┐рдд рдирд╣реАрдВ рдХреА рдЬрд╛рддреА рд╣реИред @ v1adko рджреНрд╡рд╛рд░рд╛ рдкреНрд░рд╕реНрддрд╛рд╡рд┐рдд рд╕реБрдзрд╛рд░ рдХрдо рд╕реЗ рдХрдо рдЕрдВрдХрд┐рдд рдореВрд▓реНрдп рдкрд░ рд╕рдорд╕реНрдпрд╛ рдХрд╛ рд╕рдорд╛рдзрд╛рди рдХрд░рддреЗ рд╣реИрдВред

рдореИрдВ рд╕реЛрдЪ рд░рд╣рд╛ рд╣реВрдБ рдХрд┐ рдпрд╣рд╛рдБ рдЙрд▓реНрд▓рд┐рдЦрд┐рдд рдмреИрдХрд╡рд░реНрдб рдЕрд╕рдВрдЧрддрд┐ рдХреНрдпрд╛ рд╣реИ?
https://github.com/NodeRedis/node_redis/blob/009479537eb920d2c34045026a55d31febd1edd7/index.js#L380

рдЬреИрд╕рд╛ рдХрд┐ @maael рджреНрд╡рд╛рд░рд╛ рдЗрдВрдЧрд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рд╡реНрдпрд╡рд╣рд╛рд░ рдЬрд╛рдирдмреВрдЭрдХрд░ рдкреНрд░рддреАрдд рд╣реЛрддрд╛ рд╣реИ рдЬрдм retry_strategy рд╕реЗрдЯ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рддреЛ рдХреНрдпрд╛ рд╡реНрдпрд╡рд╣рд╛рд░ рдЕрдкреЗрдХреНрд╖рд┐рдд рд╣реИ, рд▓реЗрдХрд┐рди рджрд╕реНрддрд╛рд╡реЗрдЬрд╝реАрдХрд░рдг рдЧрд▓рдд рд╣реИ? рдХреНрдпрд╛ рдореБрдЭреЗ @c24w рджреНрд╡рд╛рд░рд╛ рд╕реБрдЭрд╛рдП рдЧрдП рдЕрдиреБрд╕рд╛рд░ рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЗ рд▓рд┐рдП рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХрд╛ рдЙрддреНрд╕рд░реНрдЬрди рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП?

рд╕рдВрдкрд╛рджрд┐рдд рдХрд░реЗрдВ: рдЬреИрд╕рд╛ рдХрд┐ рдореИрдВ рдкреИрдХреЗрдЬ рдореЗрдВ рдЦреБрджрд╛рдИ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ, рдореБрдЭреЗ рдПрд╣рд╕рд╛рд╕ рд╣реЛ рд░рд╣рд╛ рд╣реИ рдХрд┐ рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ рдЙрддреНрд╕рд░реНрдЬрди рдХрд░рдирд╛ рд╢рд╛рдпрдж рдЖрдЧреЗ рдХрд╛ рд░рд╛рд╕реНрддрд╛ рдирд╣реАрдВ рд╣реИред рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдореБрдЭреЗ рдЙрд▓реНрд▓рд┐рдЦрд┐рдд рдмреНрд░реЗрдХрд┐рдВрдЧ рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдХреЛ рд╕рдордЭрдиреЗ рдХреА рдЬрд░реВрд░рдд рд╣реИред

рдХреЛрдИ рдЦрдмрд░ ? рдореЗрд░реА рднреА рдпрд╣реА рд╕рдорд╕реНрдпрд╛ рд╣реИред

рдХреЛрдИ рдЦрдмрд░?

рдХрд░рдирд╛ рдПрдХ рдЧрд▓рдд рд╡рд┐рдЪрд╛рд░ рд╣реИ:
js if (options.error && options.error.code === 'ECONNREFUSED') { // End reconnecting on a specific error and flush all commands with // a individual error return Math.min(options.attempt * 100, 3000); }

рдПрдХ рд╣реА рд╕рдорд╕реНрдпрд╛ рд╣реИ, retry_Strategy рддреНрд░реБрдЯрд┐ рдШрдЯрдирд╛ рдХреЛ рдЯреНрд░рд┐рдЧрд░ рдирд╣реАрдВ рдХрд░ рд░рд╣рд╛ рд╣реИ, рдЕрднреА рддрдХ рдХреЛрдИ рдлрд┐рдХреНрд╕ рдирд╣реАрдВ рд╣реИ?

рдХреНрдпрд╛ рдХреЛрдИ рд╕рдлрд▓ рд╣реБрдЖ?

рд╣рдордиреЗ рдЗрд╕рдХреЗ рдмрдЬрд╛рдп рдЕрдкрдиреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЛ https://github.com/luin/ioredis рдкрд░ рд╕реНрд╡рд┐рдЪ рдХрд░ рджрд┐рдпрд╛, рдЬрд┐рд╕рд╕реЗ рдХреБрдЫ рд╕реБрдзрд╛рд░ рд╣реБрдП (рдореВрд▓ рд╡рд╛рджреЗ, рдЖрд▓рд╕реА рдХрдиреЗрдХреНрдЯ (рд░реЗрдбрд┐рд╕ рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЛ рдЗрдВрд╕реНрдЯрд╛рд▓ рдХрд░рддреЗ рд╕рдордп рдХрдиреЗрдХреНрд╢рди рдЦреЛрд▓рдиреЗ рд╕реЗ рдмрдЪреЗрдВ, рд╣рдореЗрдВ рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЛ рдареАрдХ рдЙрд╕реА рддрд░рд╣ рд╕реЗ рд╕рдВрднрд╛рд▓рдиреЗ рдореЗрдВ рдорджрдж рдХрд░рддрд╛ рд╣реИ рдЬрд╣рд╛рдВ рд╣рдореЗрдВ рдЪрд╛рд╣рд┐рдП)), рдФрд░ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХреЛрдб рдХреЛ рдЪрд▓рд╛рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ:

let cachedItem;

  try {
    logger.debug(`Fetching GraphCMS query in redis cache...`);
    // XXX If fetching data from redis fails, we will fall back to running the query against GraphCMS API in order to ensure the client gets the data anyway
    cachedItem = await redisClient.get(body);
  } catch (e) {
    logger.debug(`An exception occurred while fetching redis cache.`);
    logger.error(e);
    epsagon.setError(e);
  }

рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд utils/redis.js рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛:

import { createLogger } from '@unly/utils-simple-logger';
import Redis from 'ioredis';
import epsagon from './epsagon';

const logger = createLogger({
  label: 'Redis client',
});

/**
 * Creates a redis client
 *
 * <strong i="11">@param</strong> url Url of the redis client, must contain the port number and be of the form "localhost:6379"
 * <strong i="12">@param</strong> password Password of the redis client
 * <strong i="13">@param</strong> maxRetriesPerRequest By default, all pending commands will be flushed with an error every 20 retry attempts.
 *          That makes sure commands won't wait forever when the connection is down.
 *          Set to null to disable this behavior, and every command will wait forever until the connection is alive again.
 * <strong i="14">@return</strong> {Redis}
 */
export const getClient = (url = process.env.REDIS_URL, password = process.env.REDIS_PASSWORD, maxRetriesPerRequest = 20) => {
  const client = new Redis(`redis://${url}`, {
    password,
    showFriendlyErrorStack: true, // See https://github.com/luin/ioredis#error-handling
    lazyConnect: true, // XXX Don't attempt to connect when initializing the client, in order to properly handle connection failure on a use-case basis
    maxRetriesPerRequest,
  });

  client.on('connect', function () {
    logger.info('Connected to redis instance');
  });

  client.on('ready', function () {
    logger.info('Redis instance is ready (data loaded from disk)');
  });

  // Handles redis connection temporarily going down without app crashing
  // If an error is handled here, then redis will attempt to retry the request based on maxRetriesPerRequest
  client.on('error', function (e) {
    logger.error(`Error connecting to redis: "${e}"`);
    epsagon.setError(e);
  });

  return client;
};

рдФрд░ utils/redis.test.js рдлрд╝рд╛рдЗрд▓:

import { getClient } from './redis';

let redisClient;
let redisClientFailure;

describe('utils/redis.js', () => {
  beforeAll(() => {
    redisClient = getClient();
    redisClientFailure = getClient('localhost:5555', null, 0); // XXX This shouldn't throw an error because we're using lazyConnect:true which doesn't automatically connect to redis
  });

  afterAll(async () => {
    await redisClient.quit();
    await redisClientFailure.quit();
  });

  describe('should successfully init the redis client', () => {
    test('when provided connection info are correct', async () => {
      // Environment variables are from the .env.test file - This tests a localhost connection only
      expect(redisClient.options.host).toEqual(process.env.REDIS_URL.split(':')[0]);
      expect(redisClient.options.port).toEqual(parseInt(process.env.REDIS_URL.split(':')[1], 10));
      expect(redisClient.options.password).toEqual(process.env.REDIS_PASSWORD);
    });

    test('when connection info are incorrect', async () => {
      expect(redisClientFailure.options.host).toEqual('localhost');
      expect(redisClientFailure.options.port).toEqual(5555);
    });
  });

  describe('should successfully perform native operations (read/write/delete/update)', () => {
    test('when using async/await (using native node.js promises)', async () => {
      const setResult = await redisClient.set('key-1', 'value-1');
      expect(setResult).toEqual('OK');

      const result = await redisClient.get('key-1');
      expect(result).toEqual('value-1');

      const delResult = await redisClient.del('key-1');
      expect(delResult).toEqual(1);

      const setResultB = await redisClient.set('key-1', 'value-1b');
      expect(setResultB).toEqual('OK');

      const resultB = await redisClient.get('key-1');
      expect(resultB).toEqual('value-1b');

      const setResultC = await redisClient.set('key-1', 'value-1c');
      expect(setResultC).toEqual('OK');

      const resultC = await redisClient.get('key-1');
      expect(resultC).toEqual('value-1c');
    });
  });

  describe('should allow to catch an error when failing to open a connection to redis, in order to gracefully handle the error instead of crashing the app', () => {
    test('when connection info are incorrect', async () => {
      expect(redisClientFailure.options.host).toEqual('localhost');
      expect(redisClientFailure.options.port).toEqual(5555);

      try {
        await redisClientFailure.set('key-1', 'value-1'); // This should throw an error, because the connection to redis will be made when executing the
        expect(true).toBe(false); // This shouldn't be called, or the test will fail
      } catch (e) {
        expect(e).toBeDefined();
        expect(e.message).toContain('Reached the max retries per request limit');
      }
      await redisClientFailure.quit();
    });
  });
});

рдПрдирд╡реА рдЪрд░:

REDIS_URL=localhost:6379
REDIS_PASSWORD=mypasswordissostrong
рдХреНрдпрд╛ рдпрд╣ рдкреГрд╖реНрда рдЙрдкрдпреЛрдЧреА рдерд╛?
0 / 5 - 0 рд░реЗрдЯрд┐рдВрдЧреНрд╕

рд╕рдВрдмрдВрдзрд┐рдд рдореБрджреНрджреЛрдВ

Stono picture Stono  ┬╖  6рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

Atala picture Atala  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

shmendo picture shmendo  ┬╖  6рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

lemon707 picture lemon707  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

abhaygarg picture abhaygarg  ┬╖  5рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ