Files
railwaysystem/docs/development/dms-r3/06_authorization_state_machine.md
T

10 KiB
Raw Blame History

06 门锁授权与异步操作状态机设计 (Authorization State Machine)

语义铁律:DMS HTTP 200 success: true 仅代表“请求已保存/已受理 (REQUEST_ACCEPTED)”,绝不代表“门锁设备执行成功 (DEVICE_SUCCESS)”! 门锁生效滞后性:门锁作为电池供电的无线物联网终端,下发指令需要经过网关转发与微功耗空中唤醒,官方明确要求调用成功 10 秒后再行查询操作状态。 设计目标:建立双层解耦状态机(业务授权状态 vs 设备操作状态),消除状态混淆。


1. 双层状态体系解耦定义

必须区分两个不同生命周期的状态机:

  1. 门禁授权业务状态 (DoorAuthorizationStatus):站在学员与住宿业务视角,表达该住宿事实当前是否具备开门权限。
  2. 外部硬件操作状态 (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)

  1. 触发下发:适配器调用 /rest/doorlock/online-password-key/create。
  2. 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。
  3. 轮询调度器等待 10 秒:调用 /rest/doorlock/query-operation-status(入参 requestType = 1, operationId = ...)。
  4. 轮询响应:
    {
      "success": true,
      "data": {
        "operationStatus": "success"
      }
    }
    
    本地动作:更新操作记录为 SUCCESS,授权主表推进为 ACTIVE(生效可用)。

4.2 设备超时分支 (Timeout Handling)

  • 若 10 秒后轮询返回:
    {
      "success": true,
      "data": {
        "operationStatus": "timeout",
        "message": "Device response timeout"
      }
    }
    
  • 判定规则:门锁可能休眠过深、网关信号不佳或网关离线。
  • 系统动作:
    1. 不得无限循环调用。
    2. 若配置了自动补偿,可追加 1 次重试查询;若依然超时,将操作置为 TIMEOUT,授权主表置为 ISSUE_FAILED。
    3. 页面以警告色徽标展示“设备下发超时”,提供【重新下发】按钮供管理员现场排障。

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 映射。