10 KiB
10 KiB
06 门锁授权与异步操作状态机设计 (Authorization State Machine)
语义铁律:DMS HTTP 200
success: true仅代表“请求已保存/已受理 (REQUEST_ACCEPTED)”,绝不代表“门锁设备执行成功 (DEVICE_SUCCESS)”! 门锁生效滞后性:门锁作为电池供电的无线物联网终端,下发指令需要经过网关转发与微功耗空中唤醒,官方明确要求调用成功 10 秒后再行查询操作状态。 设计目标:建立双层解耦状态机(业务授权状态 vs 设备操作状态),消除状态混淆。
1. 双层状态体系解耦定义
必须区分两个不同生命周期的状态机:
- 门禁授权业务状态 (
DoorAuthorizationStatus):站在学员与住宿业务视角,表达该住宿事实当前是否具备开门权限。 - 外部硬件操作状态 (
ExternalOperationStatus):站在异步任务与设备网络视角,表达向 DMS 派发的具体单次指令的执行进展。
2. 状态映射与状态定义字典
2.1 门禁授权业务状态 (DoorAuthorizationStatus)
| 本地业务状态枚举 | 业务含义 | 允许的操作 |
|---|---|---|
UNISSUED (待下发) |
住宿已确认,尚未向门锁发起授权下发请求 | 下发授权 (grant) |
ISSUING (下发中) |
已向 DMS 发送创建钥匙请求,已获得 operationId,正在等待 10 秒后对账确认 |
刷新状态、等待轮询 |
ACTIVE (已生效/成功) |
轮询确认设备返回 operationStatus = success,学员可正常刷卡/输密码开门 |
查看凭据、撤销授权 (revoke) |
ISSUE_FAILED (下发失败) |
DMS 或设备明确返回失败,或超时重试达到上限 | 重新下发 (retry)、人工改派房间 |
REVOKING (撤销中) |
学员退宿/调房,已向 DMS 提交删除钥匙请求,正在等待对账确认 | 刷新状态、等待轮询 |
REVOKED (已注销) |
轮询确认钥匙已被设备成功删除,权限已彻底关闭 | 归档留存、不可逆 |
EXPIRED (已到达有效期) |
超过 DMS 凭据设定的 validUntil 有效期边界(离线过期机制需供应商确认) |
自动归档、主动撤权兜底 |
2.2 外部硬件异步操作状态 (ExternalOperationStatus) 与 DMS 映射
| 本地操作状态枚举 | 对应 DMS API 原始字段 | 状态说明与处理策略 |
|---|---|---|
CREATED |
内部构建指令,尚未发送 | 准备调用 HTTP 客户端 |
REQUESTED |
HTTP 请求发出,等待响应 | 网络传输中 |
ACCEPTED |
DMS 返回 success: true,携带 operationId |
记录 operationId,调度器挂起 10 秒轮询任务 |
PENDING_DEVICE |
轮询返回 operationStatus: "undone" |
设备尚未完成执行,计算下次退避轮询时间 |
SUCCESS |
轮询返回 operationStatus: "success" |
终态:设备已成功落锁/删除,触发推进业务状态 |
FAILED |
轮询返回 operationStatus: "failed" |
终态:设备返回明确失败,记录 resultDetails 与错误原因 |
TIMEOUT |
轮询返回 operationStatus: "timeout" |
终态:DMS 判定设备通信超时(10秒未响应),触发重试或报警 |
RETRY_WAIT |
遭遇可恢复异常(如网络抖动),等待下一次重试 | 依据退避算法重新放入调度队列 |
3. 门锁授权端到端生命周期状态流转图 (Mermaid)
stateDiagram-v2
[*] --> UNISSUED : 住宿安排确认 (Accommodation Confirmed)
state "授权下发阶段 (Grant Flow)" as GrantFlow {
UNISSUED --> ISSUING : 触发下发 (报到或临近入住)
state ISSUING {
[*] --> Op_Requested : 调用 POST /online-password-key/create
Op_Requested --> Op_Accepted : DMS 返回 200 (获得 operationId)
Op_Accepted --> Op_Polling : 延迟等待 10 秒
Op_Polling --> Op_Undone : 查询状态返回 undone
Op_Undone --> Op_Polling : 间隔 5 秒重试 (最大3次)
}
ISSUING --> ACTIVE : 查询状态返回 success
ISSUING --> ISSUE_FAILED : 状态返回 failed 或多次 timeout
ISSUE_FAILED --> ISSUING : 管理员手动重试 / 定时补偿重试
}
state "正常使用阶段 (Active Use)" as ActiveUse {
ACTIVE --> ACTIVE : 门锁正常开门 / 查询电量信号
ACTIVE --> EXPIRED : 超过 validUntil 有效期边界
}
state "权限注销阶段 (Revoke Flow)" as RevokeFlow {
ACTIVE --> REVOKING : 学员退宿 / 提前退训 / 换房
ISSUE_FAILED --> REVOKING : 换房或作废
state REVOKING {
[*] --> Revoke_Requested : 调用 POST /online-password/delete
Revoke_Requested --> Revoke_Accepted : DMS 返回 200 (获得 operationId)
Revoke_Accepted --> Revoke_Polling : 延迟等待 10 秒
Revoke_Polling --> Revoke_Polling : undone (重试轮询)
}
REVOKING --> REVOKED : 查询状态返回 success
REVOKING --> REVOKE_FAILED : 状态返回 failed 或 timeout
REVOKE_FAILED --> REVOKING : 紧急人工重试撤销
}
REVOKED --> [*]
EXPIRED --> [*]
4. 关键流转分支与语义判定细节
4.1 成功下发分支 (Happy Path)
- 触发下发:适配器调用
/rest/doorlock/online-password-key/create。 - DMS 同步响应:
本地动作:持久化
{ "success": true, "data": { "id": 4945, "placeId": 1320, "lockId": 372, "operationId": "0872887e-464b-4f44-a0cc-057871ba0f65" } }external_key_id = 4945,创建外部操作记录(operationId = 0872887e...,status = ACCEPTED),授权主表推进为ISSUING。 - 轮询调度器等待 10 秒:调用
/rest/doorlock/query-operation-status(入参requestType = 1,operationId = ...)。 - 轮询响应:
本地动作:更新操作记录为
{ "success": true, "data": { "operationStatus": "success" } }SUCCESS,授权主表推进为ACTIVE(生效可用)。
4.2 设备超时分支 (Timeout Handling)
- 若 10 秒后轮询返回:
{ "success": true, "data": { "operationStatus": "timeout", "message": "Device response timeout" } } - 判定规则:门锁可能休眠过深、网关信号不佳或网关离线。
- 系统动作:
- 不得无限循环调用。
- 若配置了自动补偿,可追加 1 次重试查询;若依然超时,将操作置为
TIMEOUT,授权主表置为ISSUE_FAILED。 - 页面以警告色徽标展示“设备下发超时”,提供【重新下发】按钮供管理员现场排障。
5. Wave 1 Implementation Result (Wave 1 implemented)
- 阶段状态:Wave 1 implemented。
- 状态模型与流转控制 (
OPERATION_STATUS_MODEL):- 流转闭环:
CREATED->REQUESTED->ACCEPTED/PENDING->SUCCESS/FAILED/TIMEOUT/RETRY_WAIT(REVOKED归属于DoorAuthorization业务授权主状态,注销调用以operation_type=REVOKE发起并达成status=SUCCESS)。 - 终态保护:
SUCCESS终态达成后禁止任何逆向跳转;FAILED/TIMEOUT终态达成后禁止原记录重置为CREATED。 - 重试审计保持:重试调用通过
createRetryOperation创建自增attempt_count的全新流水记录,历史调用事实不可篡改。
- 流转闭环:
- 轮询检索接口 (
PENDING_OPERATION_QUERY):- 交付
selectPendingPollOperations,检索处于ACCEPTED、PENDING、RETRY_WAIT且next_poll_time <= NOW()的操作记录。 - 为 Wave 2 调度器提供完整数据准备,本 Wave 保持 0 调度器运行、0 HTTP 调用。
- 交付
6. Wave 2 Implementation Result (Wave 2 implemented against Mock DMS only)
- 阶段状态:Wave 2 implemented against Mock DMS only。
- 状态机与对账调度实现:
DmsOperationStatusMapper:集中映射供应商返回的设备操作状态(success->SUCCESS,undone->PENDING,failed->FAILED,timeout->TIMEOUT),未知供应商状态一律归为UNKNOWN,严禁判定为SUCCESS。ACCEPTED != SUCCESS原则强制落地:下发/删除密码接口 HTTP 200 响应仅代表平台受理并取得operationId(本地状态记录为ACCEPTED),设备执行事实必须由后续 Poller 轮询确认达成SUCCESS。DmsOperationPoller:自动从listPendingPollOperations检索任务,支持 10 秒初始延迟,单进程并发防重,终态保护不可篡改,网络错误转入RETRY_WAIT退避。
- 迁移标记:
008_RUNTIME_FIRST_RUN = NOT_EXECUTED,008_RUNTIME_SECOND_RUN = NOT_EXECUTED。RUNTIME_MIGRATION_GATE_BEFORE_PRODUCTION = REQUIRED。
7. Wave 3A Implementation Result (Wave 3A implemented against Mock DMS only)
- 阶段状态:Wave 3A Access Authorization Orchestration Dry-Run implemented against Mock DMS only。
- 厂商中立业务授权状态模型 (
AUTHORIZATION_STATUS_MODEL):- 完整定义细粒度业务授权状态枚举:
PENDING_GRANT(待下发) ->GRANTING(下发中) ->ACTIVE(已生效) ->PENDING_REVOKE(待注销) ->REVOKING(注销中) ->REVOKED(已注销),异常收敛为ERROR。 - 业务授权生命周期与单次外部操作流水(
ExternalOperation.operation_status)严格解耦:ExternalOperation达成ACCEPTED时,DoorAuthorization保持GRANTING/REVOKING,严禁直接标记为 ACTIVE / REVOKED。ExternalOperation经由异步轮询器对账达成SUCCESS时,方才正式推进DoorAuthorization为ACTIVE或REVOKED。ExternalOperation失败或超时(FAILED/TIMEOUT)时,DoorAuthorization置为ERROR并保留原业务上下文以备后续幂等重试。
- 完整定义细粒度业务授权状态枚举:
- 防迟到覆盖保护 (
STALE_OPERATION_RESULT_GUARD):- 授权主表建立
latest_operation_id与operation_version防护机制。 - 当轮询器处理旧操作流水结果时,必须强校验当前授权记录的
latest_operation_id是否依然与该流水匹配。 - 若已发起后续新操作,迟到的旧操作结果(如旧 GRANT 迟到的 FAILED 或 SUCCESS)被静默忽略,绝不覆盖新授权状态。
- 授权主表建立
- 向后兼容与双向状态映射:
TrainDormAuth内置authStatus与旧版faceSyncStatus双向同步转换,在 009 Migration 未在生产执行前无缝兼容现有 MyBatis 映射。