118 lines
8.2 KiB
SQL
118 lines
8.2 KiB
SQL
-- =========================================================================
|
||||
|
|
-- 存量升级:D20 对外房间门禁服务接口 P2(结果回调)
|
|||
|
|
--
|
|||
|
|
-- 背景:P1 只做「同步受理」,门锁下发结果没有回传渠道。P2 在授权/清除命令
|
|||
|
|
-- 进入终态时生成回调任务,按应用配置的地址上报,失败按退避重试,最终死信,
|
|||
|
|
-- 支持人工重发。本文档对应设计:doc/对外开放房间门禁服务接口设计.md §8、§9
|
|||
|
|
--
|
|||
|
|
-- 只新增一张表 + 两个字典 + 一组菜单,不改动 P1 已建的表结构。
|
|||
|
|
--
|
|||
|
|
-- 执行前置:
|
|||
|
|
-- 1) 先执行 upgrade_d20_openapi_stay.sql(P1),本脚本依赖入住单的
|
|||
|
|
-- biz_no / biz_system 字段;
|
|||
|
|
-- 2) 与 P2 代码同批次发布:代码会在入住/退房/续住时写本表,缺表会导致
|
|||
|
|
-- 这些操作在事务内报错回滚(受影响的只是接口单,平台手工单不受影响);
|
|||
|
|
-- 3) 每个接入应用需在 iot.openapi.apps[] 配置 callback-url 与 callback-secret:
|
|||
|
|
-- callback-url 为空视为「未开通回调」,不产生任务;
|
|||
|
|
-- callback-url 已配置但 callback-secret 为空时事件直接落死信(避免无签名报文),
|
|||
|
|
-- 补齐密钥后在页面人工重发即可。
|
|||
|
|
--
|
|||
|
|
-- 可重复执行:建表用 if not exists、字典与菜单先 delete 再 insert。
|
|||
|
|
-- =========================================================================
|
|||
|
|
|
|||
|
|
set names utf8mb4;
|
|||
|
|
|
|||
|
|
|
|||
|
|
-- =========================================================================
|
|||
|
|
-- 1、回调任务表
|
|||
|
|
-- status:0 待结果(已登记事件,等设备回执)1 待发送 2 已成功 3 死信
|
|||
|
|
-- revision:同一应用 + 同一单号 + 同一事件的结果版本,补偿成功后递增,
|
|||
|
|
-- 对方按 revision 最大者为最终结果(见设计稿 §8.3)
|
|||
|
|
-- callback_url 存事件产生时的配置快照,避免上线换地址后旧事件发错地方
|
|||
|
|
-- =========================================================================
|
|||
|
|
create table if not exists lock_callback_task (
|
|||
|
|
task_id bigint(20) not null auto_increment comment '任务ID',
|
|||
|
|
event_id varchar(64) not null comment '事件ID(回调头 X-Callback-Id,对方据此去重)',
|
|||
|
|
app_code varchar(32) not null comment '接入应用编码(iot.openapi.apps[].app-code)',
|
|||
|
|
event_type varchar(32) not null comment '事件类型(STAY_CHECKIN_RESULT / STAY_CHECKOUT_RESULT / STAY_EXTEND_RESULT)',
|
|||
|
|
biz_no varchar(64) not null comment '业务系统单号',
|
|||
|
|
revision int(11) not null default 1 comment '同单同事件的版本(结果变更时递增)',
|
|||
|
|
auth_id bigint(20) default null comment '关联授权ID(lock_auth.auth_id),命令终态据此落库',
|
|||
|
|
callback_url varchar(500) default null comment '回调地址(事件产生时的应用配置快照)',
|
|||
|
|
payload text comment '回调报文原文(参与签名)',
|
|||
|
|
status char(1) not null default '0' comment '状态(0待结果 1待发送 2已成功 3死信,字典 lock_callback_status)',
|
|||
|
|
retry_count int(11) not null default 0 comment '已重试次数',
|
|||
|
|
next_retry_time datetime default null comment '下次发送时间',
|
|||
|
|
last_error varchar(500) default null comment '最后一次失败原因',
|
|||
|
|
create_by varchar(64) default '' comment '创建者',
|
|||
|
|
create_time datetime comment '创建时间',
|
|||
|
|
update_time datetime comment '更新时间',
|
|||
|
|
primary key (task_id),
|
|||
|
|
unique key uk_lock_callback_event (event_id),
|
|||
|
|
unique key uk_lock_callback_rev (app_code, biz_no, event_type, revision),
|
|||
|
|
key idx_lock_callback_due (status, next_retry_time),
|
|||
|
|
key idx_lock_callback_auth (auth_id, status),
|
|||
|
|
key idx_lock_callback_list (app_code, create_time)
|
|||
|
|
) engine=innodb comment = '开放接口结果回调任务表';
|
|||
|
|
|
|||
|
|
|
|||
|
|
-- =========================================================================
|
|||
|
|
-- 2、字典
|
|||
|
|
-- =========================================================================
|
|||
|
|
delete from sys_dict_data where dict_type in ('lock_callback_status', 'lock_callback_event');
|
|||
|
|
|
|||
|
|
delete from sys_dict_type where dict_type in ('lock_callback_status', 'lock_callback_event');
|
|||
|
|
|
|||
|
|
insert into sys_dict_type (dict_name, dict_type, status, create_by, create_time, remark) values
|
|||
|
|
('回调任务状态', 'lock_callback_status', '0', 'admin', now(), '开放接口结果回调任务状态'),
|
|||
|
|
('回调事件类型', 'lock_callback_event', '0', 'admin', now(), '开放接口结果回调事件');
|
|||
|
|
|
|||
|
|
insert into sys_dict_data (dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark) values
|
|||
|
|
(1, '待结果', '0', 'lock_callback_status', '', 'info', 'Y', '0', 'admin', now(), '已登记事件,等待设备回执'),
|
|||
|
|
(2, '待发送', '1', 'lock_callback_status', '', 'primary', 'N', '0', 'admin', now(), '报文就绪,等待投递'),
|
|||
|
|
(3, '已成功', '2', 'lock_callback_status', '', 'success', 'N', '0', 'admin', now(), '对方已接收'),
|
|||
|
|
(4, '死信', '3', 'lock_callback_status', '', 'danger', 'N', '0', 'admin', now(), '重试耗尽或配置缺失,需人工处理'),
|
|||
|
|
(1, '入住结果', 'STAY_CHECKIN_RESULT', 'lock_callback_event', '', 'primary', 'Y', '0', 'admin', now(), ''),
|
|||
|
|
(2, '退房结果', 'STAY_CHECKOUT_RESULT', 'lock_callback_event', '', 'warning', 'N', '0', 'admin', now(), ''),
|
|||
|
|
(3, '续住结果', 'STAY_EXTEND_RESULT', 'lock_callback_event', '', 'success', 'N', '0', 'admin', now(), '');
|
|||
|
|
|
|||
|
|
|
|||
|
|
-- =========================================================================
|
|||
|
|
-- 3、菜单:回调任务(2140 号段,接在住宿 2130 之后)
|
|||
|
|
-- =========================================================================
|
|||
|
|
delete from sys_menu where perms like 'lock:callback:%';
|
|||
|
|
|
|||
|
|
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, route_name, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) values
|
|||
|
|
(2140, '回调任务', 2000, 13, 'callback', 'iot/callback/index', '', '', 1, 0, 'C', '0', '0', 'lock:callback:list', 'message', 'admin', CURRENT_TIMESTAMP, '开放接口结果回调任务');
|
|||
|
|
|
|||
|
|
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, route_name, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) values
|
|||
|
|
(2141, '回调查询', 2140, 1, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:callback:query', '#', 'admin', CURRENT_TIMESTAMP, ''),
|
|||
|
|
(2142, '人工重发', 2140, 2, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:callback:resend', '#', 'admin', CURRENT_TIMESTAMP, '死信重新投递');
|
|||
|
|
|
|||
|
|
|
|||
|
|
-- =========================================================================
|
|||
|
|
-- 4、执行后核对(只读,按需执行)
|
|||
|
|
-- =========================================================================
|
|||
|
|
-- 4.1 表与索引是否到位(应返回 1 行,含 3 个索引)
|
|||
|
|
-- show create table lock_callback_task;
|
|||
|
|
|
|||
|
|
-- 4.2 各状态任务数(上线初期除 0/1 外都应为 0)
|
|||
|
|
-- select status, count(1) as total from lock_callback_task group by status;
|
|||
|
|
|
|||
|
|
-- 4.3 同一单号同一事件不应出现重复 revision(应为空)
|
|||
|
|
-- select app_code, biz_no, event_type, revision, count(1) c
|
|||
|
|
-- from lock_callback_task group by app_code, biz_no, event_type, revision having c > 1;
|
|||
|
|
|
|||
|
|
-- 4.4 长期卡在「待结果」的任务(超过 24 小时,通常是被补偿任务覆盖或命令丢失)
|
|||
|
|
-- select task_id, app_code, biz_no, event_type, create_time
|
|||
|
|
-- from lock_callback_task
|
|||
|
|
-- where status = '0' and create_time < date_sub(now(), interval 1 day);
|
|||
|
|
|
|||
|
|
|
|||
|
|
-- =========================================================================
|
|||
|
|
-- 5、回滚(仅在确认不再需要回调记录后执行)
|
|||
|
|
-- =========================================================================
|
|||
|
|
-- drop table if exists lock_callback_task;
|
|||
|
|
-- delete from sys_menu where perms like 'lock:callback:%';
|
|||
|
|
-- delete from sys_dict_data where dict_type in ('lock_callback_status', 'lock_callback_event');
|
|||
|
|
-- delete from sys_dict_type where dict_type in ('lock_callback_status', 'lock_callback_event');
|