我正在使用以下代码
const redis = require('redis');
const client = redis.createClient({
url: 'redis://localhost:6379',
retry_strategy: options => new Error('Fail')
});
setInterval(() => client.incr('some-key', console.log), 5000);
针对本地 redis ( docker run --rm -p 6379:6379 redis
) 运行
在我看到第一个输出后,我杀死了 redis 以模拟断开连接。 当我看到错误出现时,我重新启动了 redis。 连接不会再次出现。 我希望在将错误刷新到离线处理程序后,客户端会尝试在下一个命令上重新连接。 相反,它保持关闭状态。 此外,它返回AbortError
而不是new Error('Fail')
。
通过 retry_strategy 的文档,如果函数返回一个数字,node_redis 似乎只会尝试重新连接。
如果您从此函数返回一个数字,则重试将恰好在该时间之后以毫秒为单位进行。
在您的情况下,您返回的是一个非数字,它不满足尝试重新连接的要求。
如果您返回一个非数字,则不会发生进一步的重试,并且所有离线命令都会出现错误。
我正在寻找的流程是:断开连接时,以 1 秒的间隔重试连接 3 次。 如果第三次它仍然断开连接,它应该返回所有未完成的命令并带有错误。 我不希望它停止尝试重新连接。
使用 README.md 中给出的示例的修改版本,您应该能够实现您想要的。 但是,一旦 3 次的最大尝试用完,客户端将不会在下一个命令上自动尝试重新连接。 我相信您需要再次手动调用createClient()
。
const client = redis.createClient({
url: 'redis://localhost:6379',
retry_strategy: (options) => {
if (options.times_connected >= 3) {
// End reconnecting after a specific number of tries and flush all commands with a individual error
return new Error('Retry attempts exhausted');
}
// reconnect after
return 1000;
}
});
是的,我忽略了这些尝试,因为这在这里没有任何区别。
所以基本上你的意思是:
let client = createClient();
function createClient () {
return redis.createClient({
url: 'redis://localhost:6379',
retry_strategy: (options) => {
client = createClient();
return new Error('Retry attempts exhausted');
}
});
}
这意味着我不能再在我的代码中传递我的 redis 客户端了?
您可以创建一个轻量级包装器来管理 redis 客户端的单例实例。
// redisClient.js
let redis = require("redis");
let client = null;
const options = {
url: 'redis://localhost:6379',
retry_strategy: (options) => {
client = null;
return new Error("Redis client connection dropped.");
}
};
module.exports = {
getClient: () => {
if (client == null) {
client = redis.createClient(options);
}
return client;
}
};
使用:
// usage
let client = require("redisClient.js");
client.getClient().get("some key");
client.getClient().set("some key", "some value");
我想这与在重试策略中调用createClient()
非常相似,但我不是那种方法的忠实粉丝。
如果您想减少一直调用getClient()
的需要,您可以制作一个大型包装器来包装所有 redis 调用,例如get()
、 set()
等,并且在这些方法中的每一种中调用getClient()
。 然而,这种getClient()
方法是一种非常常见的懒惰而不是急切地管理连接的方法。
当然,但是如果您无论如何都必须将它包装在额外的重试包装器中,那么为什么这个库根本提供任何重试策略?
我不是作者,所以我不确定 retry_strategy 的具体实现背后的动机。 在我自己使用 node_redis 时,我发现 retry_strategy 的当前功能很有用,但我同意它无论如何都缺乏自动重试的能力。 在我的使用中,我一直从 retry_strategy 返回一个数字并且从不返回错误,因为我总是希望进行连接尝试。 但是,我确实从 retry_strategy 中记录了错误。
这样的事情怎么样? https://github.com/viglucci/node_redis/tree/feature-reconnect-after-flush#retry_strategy -example
var 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');
}
// attempt reconnect after retry_delay, and flush any pending commands
return {
retry_delay: Math.min(options.attempt * 100, 3000),
error: new Error('Your custom error.');
}
}
});
从概念上讲很有意义。 实现这一点的另一种方法是将其分为两种策略:
var client = redis.createClient({
// this strategy handles the pending redis commands when the connection goes down
flush_strategy (options) {
if (options.attempt >= 3) {
// flush all pending commands with this error
return new Error('Redis unavailable')
}
// let the connection come up again on its own
return null;
},
// this strategy handles the reconnect of a failing redis
retry_strategy (options) {
if (options.total_retry_time > 1000 * 60 * 60) {
// The connection is never going to get up again
// kill the client with the error event
return new Error('Retry time exhausted');
}
// attempt reconnect after this delay
return Math.min(options.attempt * 100, 3000)
}
});
我真的不喜欢flush_strategy
这个名字,但可以想出更好的名字。
哦有趣。 您在这里建议的感觉更像是将当前的retry_strategy
重命名为connection_strategy
并使用现有的retry_strategy
作为您所说的flush_strategy
。
var client = redis.createClient({
// this strategy handles reconnection
connection_strategy (options) {
if (options.total_retry_time > 1000 * 60 * 60) {
// The connection is never going to get up again
// kill the client with the error event
return new Error('Retry time exhausted');
}
// attempt reconnect after this delay
return Math.min(options.attempt * 100, 3000)
},
// this strategy handles the pending redis commands when the connection goes down
retry_strategy (options) {
if (options.attempt >= 3) {
// flush all pending commands with this error
return new Error('Redis unavailable');
}
// let the client attempt the commands once a connection is available
return null;
},
});
实施: https :
@Janpot你能详细说明需要的用例吗? 我试图减少选项的数量以使其更易于使用,而retry_strategy
已经是一个强大的选项。
@viglucci感谢您在这里回答并提供良好的反馈! 我个人喜欢你的建议,即返回一个对象,以防万一这将被实施。 尽管我计划很快开设一个 v3 分支,但这并不是真正的重大变化。 目前,实现许多新功能非常麻烦,删除所有不推荐使用的东西会有很大帮助。
@BridgeAR现在几乎是这样,如果 redis 连接由于某种原因中断,我的所有命令都会挂起。 假设我对 redis 正在执行的操作有一个回退,那么该回退也会挂起。 我宁愿让 redis 在几次重试后返回一个错误,我可以捕获并使用回退。 这并不意味着我不希望客户端停止尝试连接。 Redis 可能会在一分钟内恢复。
我只是没有看到当前行为的意义。 您在重试处理程序中返回一个错误,然后您的客户端就永远死了。 除非您为每个命令创建一个客户端,否则谁需要这种行为?
或者我可能看不到那个当然的用例😄
@BridgeAR谢谢。 好吧,如果您有一个“通向 V3”的路线图,其中包含一些简单的任务,例如删除对配置参数的支持/删除弃用警告等,那么您有兴趣提交拉取请求。 可能无法处理大型工作,例如添加对其他 redis 命令的支持,但是如果 V3 功能分支可用,我可能会做一些简单的清理工作,如果它们对 PR 开放的话。
@viglucci我邀请作为合作者。 我很快就会制定一个计划
+1 以解决此问题。
我正在使用 Express,虽然我的retry_strategy
仍在返回整数以在将来再次尝试连接,但命令(和 Web 请求)继续堆积/备份而不是抛出一些东西以便他们可以得到继续他们的生活......希望在策略说放弃或其他任何事情之前_最终_重新建立联系。
这能实现吗? @Janpot你有没有发现目前可以解决这种情况的任何东西?
也许带有enable_offline_queue
和/或retry_unfulfilled_commands
选项的东西可以做到这一点?
感谢大家的辛勤工作和帮助!
在这里快速更新。
我将enable_offline_queue = false
到我的createClient
选项中,它似乎已经完成了我想要的操作,即:
“继续尝试基于retry_strategy
函数重新连接到我的 Redis 服务器,但在此期间尝试使用客户端时立即抛出错误响应。然后,如果能够重新连接,只需重新开始工作”。
仅供参考:在get
调用中出现以下错误: AbortError: SET can't be processed. Stream not writeable.
对于我用作数据库和我的应用程序之间的直接层,这应该没问题。 很高兴知道是否有更“强大”的解决方案,其中:
retry_strategy
继续尝试重新连接这里可能需要考虑很多艰难的场景......
@新屋,
谢谢你提到这一点。 我们希望我们的应用程序具有相同的行为,您的解决方案可以立即向调用方返回错误,但允许我们无限期地重试连接。
谢谢@newhouse ,我不确定我是否会找到这个。
IMO 这应该是默认行为,或者至少在retry_strategy
周围的文档中明确指出。 如果您认为后者合理,请告诉我,我将打开一个 PR 来添加文档。
@bwhitty任何人的文档公关都将是最受欢迎的👍
使用enable_offline_queue = false
一个问题是,在调用createClient
之后立即发送的命令,但在实际打开连接之前也会失败。
使用
enable_offline_queue = false
一个问题是,在调用createClient
之后立即发送的命令,但在实际打开连接之前也会失败。
@jkirkwood听起来您想推迟尝试发送您的第一个命令,直到发出ready
事件(或类似的适当事件)?
最有用的评论
在这里快速更新。
我将
enable_offline_queue = false
到我的createClient
选项中,它似乎已经完成了我想要的操作,即:“继续尝试基于
retry_strategy
函数重新连接到我的 Redis 服务器,但在此期间尝试使用客户端时立即抛出错误响应。然后,如果能够重新连接,只需重新开始工作”。仅供参考:在
get
调用中出现以下错误:AbortError: SET can't be processed. Stream not writeable.
对于我用作数据库和我的应用程序之间的直接层,这应该没问题。 很高兴知道是否有更“强大”的解决方案,其中:
retry_strategy
继续尝试重新连接这里可能需要考虑很多艰难的场景......