| title | 快速开始 |
|---|---|
| description | 用 npm 安装 Queuebit,运行“批量生成收据”示例,核对提交去重、分页状态、业务回执和完成通知。 |
本页从一个新 Node.js 应用开始,运行“批量生成收据”任务:把一份订单快照按页读取,生成稳定业务键的收据,提交分页进度,并在 Run 成功后交付完成通知。
本页使用一个 Node.js 进程同时提交和消费任务。先跑通这条路径,再进入持久业务存储、多进程消费者和恢复示例。
:::warning 教学示例的边界 Queuebit 的 Run、state、重试和回调记录保存在真实 Redis 中;本页的订单快照、回执和通知 sink 为了入门可读,仍由当前进程里的 Map 实现。它说明 API 顺序和幂等合同,不是跨进程恢复或生产存储方案。 :::
- Node.js 22 或更新版本。先执行
node --version,不要用 Node.js 20 运行 SDK。 - 可用的 npm。
- Redis 7.2 或更新版本,使用独立主节点,
maxmemory-policy为noeviction。本页连接本机127.0.0.1:6379,不使用 Cluster。
已有 Redis 时,确认版本和配置,不要为了示例清空数据或修改共享服务。没有 Redis 时,可在 Linux / WSL 的单独终端启动一个仅供本页使用的实例:
redis-server --bind 127.0.0.1 --port 6379 --maxmemory-policy noeviction端口已占用时不要终止原进程,可另选端口,并将同一个端口传给后面的应用命令。示例不配置 Redis 服务器断电耐久性;生产环境仍需独立评估持久化、备份和故障切换的 RPO。
在你的应用目录中安装 Queuebit:
mkdir receipt-demo
cd receipt-demo
npm init -y
npm install queuebit如果当前公开 npm 包还没有匹配本文档的 API,那是发布前置条件,不是读者需要改成本地构建包。维护者的候选包验证会在测试里单独完成,不写进用户路径。
在 receipt-demo 中创建 app.mjs,复制下面的全部代码。.mjs 可直接交给 Node.js 执行,不需要额外配置 TypeScript 编译器。
这里有三个关键顺序:
queue.define()必须在queue.ready()之前调用,任务定义随后被冻结。- 每页先写业务回执,再用
ctx.next({ afterSourceId })提交本页进度;空页返回ctx.end()。 - Run 达到
success后,还要单独等待callbacks.delivered,最后在finally中关闭队列。
连接默认端口:
node app.mjs若使用其他端口,例如 6380:
node app.mjs redis://127.0.0.1:6380应用会输出以下信息。异步日志的先后顺序可能不同,断言核对的是实际状态,不依赖打印顺序:
已提交:snapshot=receipt-demo-2026-09-14,created=true
提交去重:false,同一 runId=true
生成回执:receipt-ORD-20260914-001 / C-001 / CNY 129.90
生成回执:receipt-ORD-20260914-002 / C-002 / CNY 259.00
生成回执:receipt-ORD-20260914-003 / C-001 / CNY 88.00
生成回执:receipt-ORD-20260914-004 / C-003 / CNY 43.10
生成回执:receipt-ORD-20260914-005 / C-004 / CNY 199.00
生成回执:receipt-ORD-20260914-006 / C-002 / CNY 76.00
完成通知:receipt-demo-2026-09-14
核对:6 条业务回执,1 条完成通知,状态 success
关闭:closed,timedOut=false
同一个提交参数和幂等键在本次运行中提交两次,第二次返回同一个 runId 和 created: false。三页订单处理完后,下一次执行读到空页,才由 ctx.end() 结束。
应用会等待最多 30 秒核对结果;没有达到预期就抛错,而不是打印“成功”后静默退出。若 Redis 是你专为示例在独立终端启动的,验证后在那个终端按 Ctrl+C 关闭它。不要关闭他人或其他应用正在使用的服务。
| 对象 | 本页含义 | 不能混淆的边界 |
|---|---|---|
query.snapshotId |
要处理哪份订单快照 | 不是会随翻页改变的游标 |
state.afterSourceId |
已确认页的最后一个订单来源 ID | 不是外部写入事务的提交记录 |
idempotencyKey |
重复提交映射到同一 Run | 不代替每条回执的业务幂等 |
callbacks.delivered |
回调已成功返回并确认 | 不等于某个真实用户已经读到通知 |
close() |
停止本实例并等待协作退出 | 不清空 Redis,不回滚已有回执 |
业务写入之后、ctx.next() 确认进度之前,进程仍可能失败。当前页因此可能再次执行。生产实现要把业务唯一约束与结果写入放在同一个持久化事务中,或使用外部服务的幂等接口;不能先记“已处理”再单独执行外部写入。
任务执行和回调交付独立调度。run.status === 'success' 只说明运行成功;仍需检查 run.callbacks。回调可能重试,也可能进入死信。
| 现象 | 先检查什么 |
|---|---|
CONFIG_INVALID 或初始化失败 |
Redis 地址、版本、主节点角色和 noeviction;保留原始错误信息 |
QUEUE_NOT_READY |
是否漏掉了 await queue.ready() |
OUTCOME_UNKNOWN |
操作可能已生效;保留错误携带的 ID,先查询核对,不盲目换幂等键重投 |
Run 终止 或等待超时 |
查看 task.get(runId) 的 status、reason、error 和回调统计;不要将超时直接当成未执行 |
timedOut: true |
仍可能存在未退出的执行或回调;不能把 close 当作强制终止 Promise |
下一步阅读 BatchTask API,了解提交、查询、取消的完整返回值及错误处理边界。