酒店自助入驻:办理状态机与外设异常回退
证件、选房、制卡、支付任何一步失败,都要让旅客知道下一步去哪。
酒店自主入驻把前台流程搬到终端:核验证件 → 匹配订单 → 选房 → 制卡/发码 → 完成。流程长,外设多,最怕停在「灰色中间态」——订单已锁房但卡没发出去,旅客站在机器前不知道是该重试还是找人工。后端用显式状态机建模整条办理链,比 scattered if-else 更容易对接 PMS、支付与运维台。
状态机要覆盖异常
每个关键态在代码里显式定义四件事:成功迁移到哪、失败回退到哪、是否允许重试、是否需要人工接管。状态变更写流水表,记录 fromState / toState / reason / traceId,方便和 PMS 日志、支付回调对齐。
典型态设计
待验证→ 证件读取成功进待选房,失败留在本态并计数重试待制卡→ 发卡机成功进已完成,失败回待制卡而非直接已完成待人工→ 超过重试上限或外设报硬故障时进入,前台 App 可接管
例如制卡失败:订单与房态不要先锁死;应回到「可重试制卡」,屏幕提示「请联系前台补卡」,同时把 PMS 侧房态标记为「待确认入住」,避免下一旅客被分配到同一间。
外设对接
证件阅读器、发卡机、打印机、支付模块都可能超时或返回厂商私有错误码。驱动层统一封装:固定超时、重试次数、错误码映射表;业务层只处理语义化结果(Success / Retryable / Fatal),不解析底层十六进制码。
超时与重试策略
可重试错误(纸卡暂缺、读卡干扰)应指数退避,上限后转 待人工。不可重试错误(设备离线、硬件自检失败)直接转人工,避免旅客无意义循环。所有外设调用带同一 traceId,排障时可还原完整时间线。
常见坑
- 制卡成功但网络断在回写 PMS 前:本地流水先记「制卡成功、同步待确认」,定时任务补偿,而不是让旅客再扫一次证件
- 同一订单并发在两台终端办理:用订单号做分布式锁,第二台提示「已在另一终端办理中」
- 超时后直接标失败并释放房态:卡其实已吐出,造成重复发卡或空房纠纷
与 PMS 的边界
房态、订单金额以 PMS 为准,终端是执行器。状态机迁移成功后再调 PMS 接口;PMS 拒绝时要把终端态回滚到可重试点,并在 UI 展示 PMS 返回的可读原因,而不是笼统「系统错误」。
前台监控
大堂经理需要实时看到:哪台终端卡在哪一步、停留多久、最近一次外设错误是什么。值班台提供「远程重置到安全态」——不是删数据,而是把终端迁回 待验证 并解锁关联预占,避免运维只能现场拔电源。
支付与退款衔接
若终端集成预授权或押金扣款,支付状态应作为状态机独立分支,与制卡结果解耦。支付成功、制卡失败时,不能默认「钱已收流程结束」,而要进入「待退款或转人工结算」态,并在 UI 给出明确指引。退款接口同样要幂等,避免重复退。
上线前检查清单
- [ ] 任意办理记录可按
traceId查全链路 - [ ] 每种外设故障有明确 UI 文案与前台接管入口
- [ ] 幂等:同一订单重复提交不会重复锁房或重复扣款
- [ ] 终端断网可完成本地可恢复步骤,恢复后自动补偿同步
- [ ] 支付与制卡失败组合场景有定义态与 Runbook
自助不是无人,而是「异常时有人可接手」。状态机写清楚了,接手的人才知道该补哪一步;旅客体验上的「下一步去哪」,本质上就是状态机是否把异常路径设计完整。
小结
自助入驻的体验分打在异常回退是否清楚。支付、制卡、PMS 更新必须允许分步失败并重试,前台监控按 traceId 串联。上线前用高峰演练验证:终端卡住时,人工接管路径是否真的可执行。