You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Express框架中如何处理Redis连接错误

问题核心

Redis客户端实例创建为同步逻辑,但连接建立、连接失败均为异步触发事件,因此你当前同步返回实例的逻辑无法感知后续的异步连接结果,才会始终返回已定义的实例对象。

修复后完整代码

let connections = []

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

// 订阅连接事件,修改对应连接的状态
const subscribe = (connItem) => {
    const { connection: redisClient, ip, port } = connItem
    redisClient.on('error', function (err) {
        connItem.status = 'failed'
        killRedis(redisClient, ip, port)
        // 触发等待队列的错误回调
        if (connItem.waiters) {
            connItem.waiters.forEach(({ reject }) => reject(new Error(`Redis连接失败: ${err.message}`)))
            delete connItem.waiters
        }
    });
    redisClient.on('connect', function () {
        connItem.status = 'connected'
        console.log('Connected to Redis');
        // 触发等待队列的成功回调
        if (connItem.waiters) {
            connItem.waiters.forEach(({ resolve }) => resolve(redisClient))
            delete connItem.waiters
        }
    });
}

const findConnection = (ip, port) => {
    // 过滤掉已失败的连接记录
    let connection = connections.filter(i => i.ip == ip && i.port == port && i.status !== 'failed')
    if (connection && connection.length > 0) {
        return connection[0]
    } else {
        const connItem = {
            ip: ip,
            port: port,
            status: 'pending',
            connection: require('redis').createClient(port, ip, {
                no_ready_check: true,
                db: 1
            }),
            waiters: [] // 存储同个连接的并发等待回调
        }
        connections.push(connItem)
        subscribe(connItem)
        return connItem
    }
}

const createRedisClient = async (port, url) => {
    const connItem = findConnection(url, port)
    // 已经连接成功直接返回
    if (connItem.status === 'connected') {
        return connItem.connection
    }
    // 连接失败直接抛出错误
    if (connItem.status === 'failed') {
        throw new Error('Redis连接失败')
    }
    // 还在连接中,加入等待队列
    return new Promise((resolve, reject) => {
        connItem.waiters.push({ resolve, reject })
    })
}

module.exports = { createRedisClient }

核心修改点

  • 给连接池的每个记录新增status字段,标记pending/connected/failed三种状态,无需依赖Redis客户端的内部私有属性判断连接有效性
  • 新增waiters队列处理并发请求同个未就绪连接的场景,避免重复创建客户端
  • 异步返回结果,连接成功返回客户端实例,连接失败直接抛出错误,调用方可通过try/catch捕获异常

调用方式示例

// 业务代码中调用
const { createRedisClient } = require('./redis')
async function test() {
    try {
        const client = await createRedisClient(6379, '127.0.0.1')
        // 连接成功后才会执行到此处,可正常操作Redis
        client.set('test', '123')
    } catch (e) {
        // 连接失败会进入此处,可自定义业务容错逻辑
        console.error('连接Redis失败', e.message)
    }
}

内容的提问来源于stack exchange,提问作者mouchin777

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.18 12:45:04