如何处理 express 中的 redis 连接错误?

How to handle a redis connection error in express?

我有一个 express 数据库,它通过接收来自客户端的连接 ip 连接到多个 redis 服务器。

如果redis 数据库存在,则可以正常工作。我面临的问题是,如果 ip 不存在,我将收到

Error: Error: Redis connection to xxxx failed - connect ECONNREFUSED xxx

这完全可以理解,但问题是我的连接对象仍然被定义。而且我真的不知道如何将这个对象识别为失败的连接。 我可能唯一的提示可能在 connection._events.error 变量中,但它 returns a [Function]

这是我的代码

let connections = []

const killRedis = (redisClient, ip, port) => {
    redisClient.quit()
    connections = connections.filter((i) => { return i.ip !== ip && i.port != port })
}

const subscribe = (redisClient, url, port) => {
    redisClient.on('error', function (err) {
        //this is supposed to handle the error, but i dont know how to make the "undefined" value available for the createRedisClient function. Since this seems to be delayed
        killRedis(redisClient, url, port)
        return undefined;
    });
    redisClient.on('connect', function () {
        console.log('Connected to Redis');
        return redisClient;
    });
}

findConnection = (ip, port) => {
    let connection = connections.filter(i => i.ip == ip && i.port == port)

    if (connection && connection.length > 0) {

        return connection[0].connection
    } else {
        connections.push({
            ip: ip,
            port: port,
            connection: require('redis').createClient(port, ip, {
                no_ready_check: true,
                db: 1
            })
        })
        let pushedConnection = connections.filter(i => i.ip == ip && i.port == port)[0].connection
        subscribe(pushedConnection, ip, port)
        return pushedConnection
    }
}
const createRedisClient = async (port, url) => {
    let redisClient = findConnection(url, port)
    console.log(redisClient._events.error) //[Function]
    return redisClient // this is always a connection object, even if the connection is faulty
}
module.exports = { createRedisClient }

然后 findConnection returns 连接状态未知,因为 node-redis 是 asynchronous, it uses callbacks。一种解决方案是承诺您的 subscribe 函数,如下所示:

const subscribe = (redisClient, url, port) => new Promise((resolve, reject) => {
    redisClient.on('error', function (err) {
        console.log(err)
        killRedis(redisClient, url, port)
        reject(err)
    });
    redisClient.on('connect', function () {
        console.log('Connected to Redis');
        resolve(redisClient)
    });
})

然后,在 findConnection 中,您只需使用 try-catch 块处理可能的拒绝。请注意,它已被标记为 async:

findConnection = async (ip, port) =>  {
    let connection = connections.filter(i => i.ip == ip && i.port == port)

    if (connection && connection.length > 0) {

        return connection[0].connection
    } else {
        connections.push({
            ip: ip,
            port: port,
            connection: require('redis').createClient(port, ip, {
                no_ready_check: true,
                db: 1
            })
        })
        let pushedConnection = connections.filter(i => i.ip == ip && i.port == port)[0].connection
        try {
            const client = await subscribe(pushedConnection, ip, port)
            return client
        } catch (error) {
            return undefined // not sure what you want to do with rejections
        }
    }

然后,最后(也是async):

const createRedisClient = async (port, url) => {
    let redisClient = await findConnection(url, port)
    console.log(redisClient)
    return redisClient // this is undefined if there was an error connecting 
}

而不是 async-await,您始终可以使用 then-catch 等。另外,我相信 error 回调将在每个错误时调用。也就是说,在连接成功的情况下,如果稍​​后遇到任何 redis 错误,仍然会调用 killRedis。如果是故意的,好吧。否则,您可能需要重构您的逻辑,以便仅在成功建立连接后才注册连接。