Reputation: 1795
I am using Node Redis with this config:
import redis from "redis";
import { promisify } from "util";
import config from "../../appConfig";
const redisUrl = config.REDIS_URL;
const [host, port] = redisUrl.substr(8).split(":");
const RedisClient = redis.createClient({ host: host, port: Number(port) });
RedisClient.on("error", (err) => {
logger.error(err);
});
const GetAsync = promisify(RedisClient.get).bind(RedisClient);
const SetAsync = promisify(RedisClient.set).bind(RedisClient);
export { RedisClient, GetAsync, SetAsync };
I have some code which first tries reading from Redis and if that fails, tries reading from MongoDB inside a catch block. Something like this:
try {
userId = await GetAsync(idKeyStr);
} catch(err) {
userId = await GetFromMongoDB();
}
My problem is that when the connection fails, the code just gets stuck at userId = await GetAsync(idKeyStr)
. No exception is being thrown so that the code moves into the catch block. The default time till which the client attempts to reconnect is 1 hour. If within that 1 hour, the server comes up, it will reconnect and the request which was stuck will finally get handled. If it doesnt come up, that request will just be stuck for 1 hour.
If I throw an error from the callback for error
event, the application just stops, because of unhandled exception.
I found the retry_strategy
option for the createClient
method here: https://github.com/NodeRedis/node-redis This is the example given on that page:
const client = redis.createClient({
retry_strategy: function(options) {
if (options.error && 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.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 > 10) {
// End reconnecting with built in error
return undefined;
}
// reconnect after
return Math.min(options.attempt * 100, 3000);
},
});
To throw an error immediately, I modified this to:
const client = redis.createClient({
retry_strategy: function() {
return new Error("The server refused the connection");
},
});
But this stops the retries altogether, so even when the server comes up, the client has stopped connection attempts so it never reconnects.
How can I configure it so that the client continues to reconnect but any issued commands fail fast, so that my other code continues execution?
Upvotes: 1
Views: 5789
Reputation: 88
For anyone using this in 2022, the configuration name is now disableOfflineQueue
. It is set to false by default, so you have to set it to true in creatClient
.
This is how I do it in my code
import { createClient } from 'redis';
const client = createClient({
url: redisHost, // redisHost is something like redis://:@localhost:6379/1
disableOfflineQueue: true,
});
(async () => {
await client.connect();
})();
Upvotes: 4
Reputation: 1795
Setting enable_offline_queue
to false
did the trick. Found lots of similar questions but none mentioned this:
Nodejs set timeout for Redis requests
What's the default timeout of ioredis send command for any redis call
How to set read timeout on node redis client?
Finally got this solution from here: https://github.com/NodeRedis/node-redis/issues/789#issuecomment-373270272
Do keep in mind that, with enable_offline_queue
set to false, the commands that you issue while there's some connection issue with the server will never be executed.
Upvotes: 0