首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >门店多个终端同时叫号怎么不乱:排队队列的单一序号源与状态广播设计

门店多个终端同时叫号怎么不乱:排队队列的单一序号源与状态广播设计

原创
作者头像
用户5598620
发布2026-09-16 09:00:45
发布2026-09-16 09:00:45
810
举报

线下门店一旦同时有取号机、几个窗口的叫号屏、员工手持终端在操作同一个排队队列,问题就来了:两台取号机打出重复号码,两个窗口叫到同一个号,过号之后屏幕还显示在等待,顾客重取的号和原号对不上。这些看似是界面问题,根子都在“序号从哪来、状态由谁定、变更怎么同步”。这篇给一套可直接落地的排队队列设计。

一、多终端排队,乱到底乱在哪

先把典型故障归类,后面方案逐条对应:

  • 重复号:多个取号入口各自计数,并发时打出相同序号;
  • 重叫/跳号:两个窗口同时取“下一个”,叫到同一位,或漏掉中间的号;
  • 状态不一致:窗口已经叫号,大屏和顾客手机上还显示等待中;
  • 过号混乱:过号的人回来,应该重排到哪、是否优先,没有确定规则;
  • 断线错乱:叫号屏网络抖动重连后,显示的队列停留在旧状态。

共性原因是序号有多来源、状态变更没有原子性、各终端各自维护一份队列。解决思路也对应三句话:序号单一来源、状态集中管理、变更统一广播。

二、序号必须来自单一序号源

无论有多少取号入口,序号都不能在终端本地生成,必须向同一个序号源申请。实践中按“门店+业务线+日期”划分独立队列,每条队列维护一个自增序列,取号即对该序列做一次原子递增:

代码语言:bash
复制
# 以键 queue:{门店}:{业务线}:{日期}:seq 记录当日已发到的最大序号
INCR queue:store01:normal:20260916:seq

拿到的序号配合队列前缀展示(如 A023),序号只增不复用。选择序号源时把握两点:递增操作必须是原子的,避免两个请求读到同一个值;序列按自然日重置,第二天从初始号开始,避免跨天混号。业务线(如个人业务、对公业务)分开计数,不同队列互不影响。

三、用显式状态机管理排队全流程

每个号码从取走到结束,应有一条确定的状态流转路径,而不是用几个零散布尔值拼:

已取号(WAITING)→ 已叫号(CALLING)→ 办理中(SERVING)→ 已完成(DONE);任意环节可进入 过号(PASSED)或 弃号(CANCELLED),过号可被重新叫回。

队列主记录建议落库,缓存承载热状态,表结构至少包含序号、队列、状态、取号时间、各状态变更时间和所在窗口:

代码语言:sql
复制
CREATE TABLE queue_ticket (
  id           BIGINT PRIMARY KEY,
  store_id     VARCHAR(32) NOT NULL,
  queue_key    VARCHAR(32) NOT NULL,   -- 业务线+日期
  ticket_no    INT NOT NULL,           -- 当日序号
  status       VARCHAR(16) NOT NULL,   -- 状态机取值
  window_no    VARCHAR(16),
  created_at   DATETIME NOT NULL,
  called_at    DATETIME,
  finished_at  DATETIME,
  UNIQUE KEY uk_queue_ticket (queue_key, ticket_no)
);

唯一约束从存储层再兜一次底,即使上游出现异常也不会插入同一队列的重复序号。

四、叫号动作怎么保证不重叫、不跳号

“叫下一个”是并发竞争最集中的动作:多个窗口同时点,必须保证一个待叫号码只被一个窗口拿到。做法是在单一数据源上用原子操作弹出当前队首并置为已叫号,下面是一段示意的原子脚本逻辑:

代码语言:lua
复制
-- KEY: 队列有序集合(score=序号, member=号码);ARGV: 窗口号、当前时间
local waiting = redis.call('ZRANGE', KEYS[1], 0, 0)
if #waiting == 0 then return nil end
local ticket = waiting[1]
-- 只有仍处于 WAITING 才允许被叫,避免重复
local ok = redis.call('HSETNX', 'call:'..ticket, 'window', ARGV[1])
if ok == 0 then return nil end
redis.call('ZREM', KEYS[1], ticket)
redis.call('HSET', 'call:'..ticket, 'status', 'CALLING', 'at', ARGV[2])
return ticket

要点是“检查待叫+占用号码”在一个原子操作内完成,占用成功才返回号码,失败的窗口拿到空结果再重试,自然不会两个窗口叫到同一位。叫号后给一个确认时限,超时未确认办理则号码回到待叫或转过号,避免号码被“叫走却没人跟”。

五、多终端状态怎么实时一致

所有叫号、过号、完成动作都只改服务端这一份权威状态,终端不自行推算。变更发生后,由服务端向该门店所有在线终端广播状态变更事件,大屏、手持端、顾客端订阅同一频道:

代码语言:javascript
复制
// 终端订阅示意:收到事件就按服务端给的全量/增量状态渲染
subscriber.on("queue:event", (event) => {
  if (event.storeId !== currentStore) return;
  applyQueueEvent(event);          // 增量更新本地视图
  renderBoard(currentSnapshot());
});
// 断线重连不补发历史,而是拉一次该队列的权威快照对齐
subscriber.onReconnect(async () => {
  const snapshot = await fetchQueueSnapshot(queueKey, lastVersion);
  replaceWithSnapshot(snapshot);
});

两个关键设计:一是每条变更带单调递增的版本号,终端据此判断是否漏事件;二是断线重连后不信任本地缓存,直接拉一次权威快照对齐,从机制上杜绝“重连后停在旧队列”。

六、过号、重叫、转窗口怎么定规则

特殊情况要在状态机里提前定死,避免现场自由发挥:

  • 过号:叫号后超过确认时限未到,置为 PASSED 并移出待叫集合,大屏短暂提示后归入过号区;
  • 过号重叫:顾客回来不重新取号,把原号码按规则插到当前队首之后若干位(如当前号之后第三位),保留原序号并标注“重叫”;
  • 转窗口:只改 window_no、状态不变,全程留痕,不产生新号码;
  • 弃号:顾客主动离开置 CANCELLED,序号不回收,保证顺序可追溯。

七、踩坑清单

  • 取号终端本地自增序号,多入口必然重复——序号统一向单一序号源原子申请;
  • 用布尔字段拼状态,过号、重叫时无法自洽——用显式状态机;
  • “查下一个+置状态”分两步,并发下重叫——合并为一个原子操作;
  • 终端各自维护队列,网络一抖就不一致——服务端权威+事件广播;
  • 重连后只续传事件、不拉快照,漏掉的事件补不回来——重连先对齐快照;
  • 过号直接删号或重新取号,顺序无法追溯——保留原号、按规则插队。

八、工程落地建议

建议把排队能力做成门店系统里的独立服务,对内提供取号、叫号、过号、完成、查询快照五类接口,序号生成、状态流转、并发控制收敛在服务端,终端只负责展示和触发。队列热状态放缓存、主记录落库并加唯一约束,事件广播带版本号,重连以快照对齐。这套抽象不绑定具体行业,银行、政务、餐饮、医疗等需要多窗口排队的门店场景都能复用。

九、常见问题

Q:取号机断网了还能取号吗?

A:取号必须向单一序号源申请,断网时不应在本地先编号,避免恢复后重号;可短暂排队等网络恢复,或切换到备用的统一序号源。

Q:过号和弃号有什么区别?

A:过号是叫到时未响应、仍可能回来办理,保留号码可重叫;弃号是顾客明确不再办理,状态终止、序号不回收。

Q:多个业务线要共用一个队列吗?

A:通常按业务线分列计数和叫号,避免办理时长差异大的业务互相阻塞;大厅可统一展示,但序号和状态各自独立。

十、复盘清单

  • 序号是否全部来自单一原子序号源、按门店/业务线/日期分列?
  • 是否用显式状态机覆盖取号到完成及过号弃号?
  • “叫下一个”是否做到检查与占用原子化、杜绝重叫?
  • 终端是否以服务端为权威、靠带版本的事件同步、重连拉快照?
  • 过号重叫、转窗口是否有确定规则并全程留痕?

多终端排队不乱的关键,不是把界面做多复杂,而是让序号只有一个来源、状态只有一份权威、每次变更都原子且可同步。把这三点在服务端做扎实,再多取号入口和叫号窗口也能保持同一个秩序。本文为后端工程实践分享,具体实现以业务规则为准。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 一、多终端排队,乱到底乱在哪
  • 二、序号必须来自单一序号源
  • 三、用显式状态机管理排队全流程
  • 四、叫号动作怎么保证不重叫、不跳号
  • 五、多终端状态怎么实时一致
  • 六、过号、重叫、转窗口怎么定规则
  • 七、踩坑清单
  • 八、工程落地建议
  • 九、常见问题
  • 十、复盘清单
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档