0

0

Redis 多键有序列表批量读取与员工调度数据映射(Node.js 实战教程)

霞舞

霞舞

发布时间:2026-02-10 16:40:51

|

948人浏览过

|

来源于php中文网

原创

Redis 多键有序列表批量读取与员工调度数据映射(Node.js 实战教程)

本文详解如何在 node.js 中高效、安全地批量读取 redis 中多个以 user:gxxxx 格式命名的有序列表(list),并按员工 id 映射结构化返回,规避异步并发导致的客户端关闭错误及数据错位问题。

在构建高并发调度系统时,常需从 Redis 快速拉取大量员工(如 G1257, G1189)关联的排班记录——每条记录以 JSON 字符串形式存储于独立 LIST 中(键为 user:{empid})。若采用循环 + 回调方式逐个 lRange 查询(如原始代码),不仅因 Node.js 事件循环与 Redis 客户端生命周期不匹配而触发 ClientClosedError,更会因异步竞态导致结果顺序错乱、empid 映射丢失。

✅ 正确解法是:使用 Redis 事务管道(MULTI/EXEC)实现原子性批量命令提交,配合 async/await 保证执行流可控,并在结果解析阶段严格对齐原始人员顺序。

✅ 推荐实现:基于 multi.exec() 的批处理方案

以下为生产就绪的完整示例(适配 redis@4.x 及 Sequelize):

HiDream AI
HiDream AI

全中文AIGC创作平台和AI社区

下载
const { promisify } = require('util');
const { createClient } = require('redis');

// 假设 client 已全局初始化并连接成功
const client = createClient({ url: 'redis://localhost:6379' });
await client.connect(); // 确保连接建立

router.get('/scheduler', async (req, res) => {
  try {
    // 1. 查询符合条件的员工列表(如按职级筛选)
    const personnelList = await Personnel.findAll({
      where: { mgr_wrkpersonnels_designation: req.query.mgr_wrkpersonnels_designation }
    });

    if (personnelList.length === 0) {
      return res.json([]);
    }

    // 2. 构建 MULTI 批量命令:为每个 empid 发起 lRange 查询
    const multi = client.multi();
    personnelList.forEach(person => {
      const empId = person.dataValues.mgr_wrkpersonnels_empid;
      multi.lRange(`user:${empId}`, 0, -1); // 获取全部元素
    });

    // 3. 执行所有命令,返回扁平化结果数组(按入队顺序)
    const rawResults = await multi.exec();

    // 4. 解析结果:JSON.parse + 注入 empid,保持与 personnelList 索引一致
    const schedules = rawResults.map((reply, idx) => {
      if (reply instanceof Error || !Array.isArray(reply)) {
        console.warn(`Failed to fetch list for ${personnelList[idx].dataValues.mgr_wrkpersonnels_empid}:`, reply);
        return [];
      }
      const empId = personnelList[idx].dataValues.mgr_wrkpersonnels_empid;
      return reply
        .filter(item => typeof item === 'string' && item.trim())
        .map(item => {
          try {
            const parsed = JSON.parse(item);
            parsed.resource = empId; // 显式绑定员工标识
            return parsed;
          } catch (e) {
            console.error(`Invalid JSON in list user:${empId}:`, item);
            return null;
          }
        })
        .filter(Boolean); // 过滤解析失败项
    });

    res.json(schedules);

  } catch (error) {
    console.error('[Scheduler API] Redis batch read error:', error);
    res.status(500).json({ error: 'Failed to load schedules' });
  }
});

⚠️ 关键注意事项

  • 绝不混用回调与 Promise:原始错误 ClientClosedError 根源在于 forEach + callback 模式下,client 可能在所有回调执行前被意外关闭(如中间件提前结束响应)。multi.exec() 返回 Promise,天然兼容 async/await,避免竞态。
  • 索引强对齐:multi.exec() 返回结果数组严格按 multi.xxx() 调用顺序排列,因此 rawResults[i] 必然对应 personnelList[i],这是实现 empid 准确映射的基石。
  • 错误防御性处理:每个 lRange 结果可能为 Error 实例(如 key 不存在),需显式判断;JSON 解析也应 try/catch,防止单条脏数据阻断整个响应。
  • 连接管理:确保 client.connect() 在应用启动时完成,且避免在请求中重复创建/关闭 client(除非使用连接池)。
  • 性能边界:MULTI/EXEC 本质是将 N 条命令打包为一次 TCP 往返,大幅提升吞吐。但单次 lRange 若列表过长(如 >10k 元素),仍建议分页或改用 Sorted Set + ZRANGEBYSCORE 优化。

✅ 输出结构说明

最终返回为二维数组,每个子数组代表一位员工的完整排班列表,每项含原始字段(id, start, end)及新增 resource 字段(即 empid):

[
  [
    { "id": 2, "start": "2023-08-05T00:00:00", "end": "2023-08-12T00:00:00", "resource": "G1257" },
    { "id": 4, "start": "2023-08-14T00:00:00", "end": "2023-08-19T00:00:00", "resource": "G1257" }
  ],
  [
    { "id": 2, "start": "2023-08-07T00:00:00", "end": "2023-08-08T00:00:00", "resource": "G1189" }
  ]
]

此结构可直接被前端按 resource 分组渲染,兼顾性能、准确性与可维护性。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
什么是中间件
什么是中间件

中间件是一种软件组件,充当不兼容组件之间的桥梁,提供额外服务,例如集成异构系统、提供常用服务、提高应用程序性能,以及简化应用程序开发。想了解更多中间件的相关内容,可以阅读本专题下面的文章。

180

2024.05.11

Golang 中间件开发与微服务架构
Golang 中间件开发与微服务架构

本专题系统讲解 Golang 在微服务架构中的中间件开发,包括日志处理、限流与熔断、认证与授权、服务监控、API 网关设计等常见中间件功能的实现。通过实战项目,帮助开发者理解如何使用 Go 编写高效、可扩展的中间件组件,并在微服务环境中进行灵活部署与管理。

222

2025.12.18

json数据格式
json数据格式

JSON是一种轻量级的数据交换格式。本专题为大家带来json数据格式相关文章,帮助大家解决问题。

435

2023.08.07

json是什么
json是什么

JSON是一种轻量级的数据交换格式,具有简洁、易读、跨平台和语言的特点,JSON数据是通过键值对的方式进行组织,其中键是字符串,值可以是字符串、数值、布尔值、数组、对象或者null,在Web开发、数据交换和配置文件等方面得到广泛应用。本专题为大家提供json相关的文章、下载、课程内容,供大家免费下载体验。

543

2023.08.23

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

317

2023.10.13

go语言处理json数据方法
go语言处理json数据方法

本专题整合了go语言中处理json数据方法,阅读专题下面的文章了解更多详细内容。

79

2025.09.10

resource是什么文件
resource是什么文件

Resource文件是一种特殊类型的文件,它通常用于存储应用程序或操作系统中的各种资源信息。它们在应用程序开发中起着关键作用,并在跨平台开发和国际化方面提供支持。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

166

2023.12.20

php中foreach用法
php中foreach用法

本专题整合了php中foreach用法的相关介绍,阅读专题下面的文章了解更多详细教程。

161

2025.12.04

包子漫画网页版入口与全集阅读指南_正版免费漫画快速访问方法
包子漫画网页版入口与全集阅读指南_正版免费漫画快速访问方法

本专题汇总了包子漫画官网和网页版入口,提供最新章节抢先看方法、正版免费阅读指南,以及稳定访问方式,帮助用户快速直达包子漫画页面,无广告畅享全集漫画内容。

36

2026.02.10

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
进程与SOCKET
进程与SOCKET

共6课时 | 0.4万人学习

Redis+MySQL数据库面试教程
Redis+MySQL数据库面试教程

共72课时 | 6.7万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号