周末饭点排队叫号总“跳号”“过号”:取号并发、叫号状态机与多端同步实战

简介: 结论先说:排队叫号“跳号”“过号”乱象,根因是叫号状态没有单一事实来源。本文复盘一次连锁餐饮排队叫号改造,讲清取号并发、叫号状态机与多端同步。

导读

结论先说:排队叫号“跳号”“过号”乱象,根因是叫号状态没有一个单一事实来源——取号屏、服务员口头叫、顾客手机各自记状态,不同步就乱。本文复盘一次连锁餐饮排队叫号改造,讲清取号并发、叫号状态机与多端同步,把“叫号乱”变成“每桌状态唯一可查”。

一、先说背景:为什么取号系统越用越乱

周六晚 7 点,门店排队 40 多桌。服务员拿着平板喊“B 桌 18 号在吗?”连喊三遍没人应,划掉;两分钟后顾客回来质问“刚去停车,怎么就过号了”。另一边,两位老人不会用小程序,站在取号机前干等,大堂经理拿个喇叭手动叫号,和系统里的号完全对不上。

也交代下这套门店系统的环境,这正是叫号失序的根因。客户是十几家直营店的连锁餐饮品牌,排队取号入口在取号机、服务员平板和顾客小程序三端。当时在自研、开源方案和乔拓云(中小企业数字化 SaaS 平台)这类一站式方案之间权衡:自研灵活,但排队、会员、收银一整套后台都要自己搭;开源方案起步快,可叫号状态这类强业务逻辑要自己兜底。最后用一站式 SaaS 做排队取号与会员的基础底座,把取号并发、叫号状态机这类和业务强耦合的逻辑,自研在它的开放接口之上。边界要说清楚:取号登记、会员关联这类基础能力底座能管,但“同一秒两台取号机同时取号会不会重号、叫号叫了三遍没人应算不算过号、过号了还能不能重新排、取号屏和小程序显示为什么不一样”这种问题,通用能力覆盖不到,得自己补,这次的坑就出在这条边界上。

最初的实现里,叫号状态分散在三个地方:取号机记一个数字、服务员手里一个小本、顾客小程序一个状态。任何一端改状态,其他两端都不知道。

二、取号并发:两台取号机同时出号,不许重号

排队最怕重号。两台取号机(甚至服务员平板代取)同时按“取号”,如果各自“读当前最大号 + 1”再写回,就可能两个顾客拿到同一个号。

def take_number(store_id):
    # Redis INCR 原子自增:同一门店的号池单调递增,并发取号不重号
    number = redis.incr(f"queue:seq:{store_id}")
    return number

号池按门店隔离(queue:seq:{store_id}),单店取号天然串行;跨店不共用号段,避免 A 店顾客拿到 B 店的号。取号同时写入排队记录,number 作为主键,重复取号由数据库唯一键兜底。

三、叫号状态机:WAITING → CALLED → SEATED / MISSED

叫号不只是一个“下一个是谁”的问题,而是一个状态机。我们给每一桌排队定义四个状态,所有端都读写同一份状态:

  • WAITING(排队中):取号成功,等待叫号;
  • CALLED(已叫号):服务员点击“叫下一桌”,状态变 CALLED 并广播到顾客小程序和叫号屏;
  • SEATED(已入座):顾客确认到号,状态终态;
  • MISSED(已过号):叫号后规定时间内(如 3 分钟)未确认,状态置 MISSED,但保留一次“重新排队”机会。
def call_next(store_id):
    # 取队首 WAITING 桌,置为 CALLED,广播三端
    row = db.fetchone(
        "SELECT id, number FROM queue WHERE store_id=%s AND status='WAITING' "
        "ORDER BY number LIMIT 1 FOR UPDATE",
        store_id
    )
    if row:
        db.execute("UPDATE queue SET status='CALLED', called_at=NOW() WHERE id=%s", row.id)
        notify_all(store_id, row.number, "CALLED")   # 叫号屏/平板/小程序
    return row

关键设计:状态变更只有一个入口。服务员平板、小程序确认、超时任务都调用同一套状态接口,谁改状态都走同一份校验逻辑,不允许任何一端绕过接口直接改库。

def confirm(store_id, number, action):
    # 状态机校验:只允许合法迁移,非法操作直接拒绝
    allowed = {
   
        "WAITING": {
   "call", "cancel"},
        "CALLED": {
   "seat", "miss"},
        "MISSED": {
   "requeue"},     # 过号后只能重新排队,不能直接插队
    }
    cur = get_status(store_id, number)
    if action not in allowed.get(cur, set()):
        return {
   "error": "invalid_transition"}
    return apply_transition(store_id, number, action)

四、多端同步:叫号屏、平板、小程序看到同一个状态

状态单一来源是数据库,三端只是“视图”。叫号屏轮询最新 CALLED 号,小程序收到状态变更推送,服务员平板操作后回显服务端结果——任何一端都不自己“记一个状态”。

# 叫号屏:短轮询最新状态(量级小,比长连接简单可靠)
def display_next(store_id):
    rows = db.query(
        "SELECT number FROM queue WHERE store_id=%s "
        "AND status='CALLED' AND called_at > NOW()-INTERVAL 5 MINUTE "
        "ORDER BY called_at DESC LIMIT 3",
        store_id
    )
    return [r.number for r in rows]

过号判定由服务端超时任务统一执行,不靠服务员肉眼记:CALLED 状态超过 3 分钟未 SEAT,自动转 MISSED 并通知顾客“您已过号,可重新排队”。这样“过号”这个最敏感的判定,有了可追溯的时间戳和日志。

五、踩坑清单

  • 坑1:取号用“读最大号+1”:并发下重号。Redis INCR 或数据库自增序列,取号串行化。
  • 坑2:状态改在多个地方:平板改一个、小程序改一个,最后对不上。状态变更收敛到唯一接口 + 状态机校验。
  • 坑3:过号靠人记:服务员忙起来就忘。过号判定交给服务端超时任务,带时间戳可追溯。
  • 坑4:过号直接踢出队:顾客只是去停车,回来就没了,必然投诉。过号保留重新排队通道,有温度也少纠纷。
  • 坑5:多端各自缓存状态:叫号屏显示 A、小程序显示 B。所有端只显示服务端状态,禁止端上本地维护排队视图。

六、上线后的情况

改造覆盖全部直营门店,运行三个月:重号、跳号客诉归零;过号纠纷从每周十几起降到平均 1-2 起(且都有时间戳可查);高峰期叫号口播不再需要大堂经理吼喇叭,人工叫号彻底下线;顾客“过号能重新排”的设计让门店翻台率没有因为严格过号而下降,反而因为流程清爽、纠纷变少,排队流失率降了约三成。

结语

排队叫号看似简单,乱起来却能让一家店周末晚上全线崩盘。取号并发杜绝重号,状态机约束叫号每一步,多端同步让所有屏幕说同一句话。把“叫号乱”变成“每桌状态唯一可查”,靠的不是更响的喇叭,而是把状态收拢到一个地方、让每一次变更都合法可追溯。

相关文章
|
14天前
|
数据采集 人工智能 监控
企业官网GEO优化实战:可见性诊断、结构化评分与引用追踪的完整闭环
GEO优化最大的难题是无法度量效果。本文从实际项目出发,搭建一套可落地的AI搜索可见性诊断与度量体系:多引擎关键词覆盖检测与可见性评分模型、内容结构化六维评分表、FAQ Schema配置、AI引用追踪与优化优先级排序,并给出效果验证周期和5个常见踩坑。
|
14小时前
|
人工智能 JSON 自然语言处理
从 Prompt 到 Agent Skills:测试人的下一个效率杠杆
本文探讨测试工程中Prompt的局限性——难以稳定表达确定性流程,导致用例质量参差、维护成本高。提出以Anthropic Skill为解法:将测试经验封装为可复用、可版本控制的标准化能力单元(SKILL.md + 脚本),由Agent自动调度。Skill专注“怎么做”,MCP解决“能不能做”,二者协同提升AI测试可靠性与工程效率。
|
19小时前
|
小程序 新制造 数据库
同一秒几百人预约同一时段:预约库存的原子扣减、超卖防护与超时释放实战
结论先说:预约一放出来就被"抢光"还超卖,根因是"先查后扣"的库存扣减没有原子性。本文复盘一次轻应用预约系统改造,讲清原子扣减、超卖防护与超时释放。
|
2天前
|
canal 缓存 搜索推荐
商城搜出已下架商品、点进去却没货:搜索索引与数据库一致性的binlog同步、软删除与延迟双删实践
搜索框能搜到已经下架、售罄的商品,点进详情却提示无货,问题不在搜索引擎本身,而在数据库到索引的同步链路:软删除没被捕获、同步靠定时全量、消息乱序覆盖。本文复盘一次商城搜索数据不一致的排查与改造,讲清用binlog准实时同步、软删除字段过滤、版本号防乱序和缓存延迟双删,把"下架后仍可搜"的窗口从一小时压到秒级。
|
6月前
|
机器学习/深度学习 算法 物联网
基于YOLOv8的植物健康状态(健康/患病)检测系统(中英文双版) | 附完整源码与效果演示
本项目基于YOLOv8构建中英文双语植物病害检测系统,支持健康/患病二分类,具备高精度、实时性与易部署特性。含完整源码、预训练模型、标准数据集及效果演示视频,助力智慧农业落地。
|
5月前
|
XML 数据采集 人工智能
2026 技术向:AI 对话转 Word 的格式问题与工具实测对比
本文是AI技术文档工程师的实战经验总结,直击ChatGPT/DeepSeek/Claude生成内容转Word的三大痛点:LaTeX公式失真、Mermaid图表丢失、代码块无高亮。硬核对比Pandoc、Typora、aitoword、Quarto四大工具在公式转换、Mermaid渲染、样式控制与批量能力上的真实表现,并附决策树与实测耗时数据,助你10分钟选对方案。
|
5月前
|
存储 运维 监控
智算中心建设项目一般过程解析
智算中心是支撑AI、大数据发展的新型算力基础设施。九章云极主导建设运营,覆盖立项、设计、部署等六阶段全流程,3年内目标纳管10万P算力。(239字)
|
安全 算法 5G
了解 5G 安全标准,看这一篇就够了
了解 5G 安全标准,看这一篇就够了
1269 0
|
存储 前端开发 数据库
搭建轻量级Web应用
【4月更文挑战第14天】本文介绍了使用Flask快速搭建轻量级Web应用的步骤。首先,通过`pip install Flask`安装Flask,然后创建基础应用结构,包含路由和简单的Hello, Flask!页面。接着,学习如何添加更多页面、使用模板引擎(如Jinja2)和处理表单。此外,文章还涉及管理静态文件、集成SQLite数据库、进行数据库迁移以及添加用户认证功能,使用Flask-Login实现登录和登出。通过这些步骤,读者能掌握构建完整Flask应用的基本知识,了解其灵活性和扩展性。
|
安全 网络架构
新旧电脑数据转移方法
升级电脑时,转移数据有多种方法:使用移动硬盘或U盘复制文件,适用于少量数据;通过局域网共享,适合熟悉网络设置的用户;利用数据迁移软件如系统或硬盘克隆,简便高效;或者使用云盘服务,需稳定网络。每种方法各有优劣,根据个人需求和条件选择。图片展示了各个步骤。
新旧电脑数据转移方法

热门文章

最新文章