build / build-push (push) Successful in 1m21s
含10-22精修: 对账有限重试(retry_count/指数退避/work_version防旧覆盖)+接缝身份(source-app-key空拒收)+应急对账闸让位FlowApplyRecoveryService+同attempt指令不重开终态。SQL未执行。
83 lines
8.2 KiB
SQL
83 lines
8.2 KiB
SQL
-- ============================================================
|
||
-- 办事大厅 · 对账任务接收与执行检查点 DDL(MySQL 5.7 兼容复核版,TASK_3)
|
||
-- 范围:一张新表 answer_reconcile_work(中心侧契约见 form-center/service/docs/answer-reconcile-v1.md)
|
||
-- 依据:任务书 TASK_3 改动点 4(SH 持久化接收任务、重复指令复用 taskId、进程重启从 checkpoint 续页)、
|
||
-- 改动点 5/6(比较四元摘要、经权威入口修复、多余行只在完整证明后退役)
|
||
-- 用途:生产 ddl-auto=none 时的升级脚本;开发期(本机 bsch_svchall,ddl-auto=update)由 Hibernate
|
||
-- 自动追加,本脚本同时是"实表应当长什么样"的评审权威(沿 fc_projection_and_apply_intent 先例)。
|
||
-- 5.7 复核要点:①无 CTE/WITH、无函数索引、无生成列、无 CHECK 约束;②utf8mb4 显式写 CHARSET/COLLATE;
|
||
-- ③<b>不建物理外键</b>——task_uuid 是中心任务的逻辑引用,本行要能在中心归档后继续留痕;
|
||
-- ④两条游标与水位同为 answer_uuid(32 位小写十六进制),锁步推进才是"多余行"可判的前提。
|
||
-- 边界纪律:本表只存<b>对账坐标与检查点</b>,不存答卷值文档——值文档归 fc_answer_projection(TASK_2),
|
||
-- 修复走 repairAuthoritative、退役走 retireAbsent,本任务不提供任何绕过它们的通道。
|
||
-- 状态纪律:接收端点的 2xx 只把 state 写成 QUEUED;COMPLETED/PARTIAL 必须来自本地扫描的真实收尾,
|
||
-- 且以 (task_uuid, attempt) 的回报为准。
|
||
-- 非幂等:MySQL 5.7 无评审友好的 CREATE TABLE IF NOT EXISTS 写法。
|
||
-- 执行前先 `SHOW TABLES LIKE 'answer_reconcile_work'` 确认表不存在。
|
||
-- ============================================================
|
||
|
||
CREATE TABLE `answer_reconcile_work` (
|
||
`work_version` BIGINT NOT NULL DEFAULT 0 COMMENT 'Local optimistic write generation',
|
||
`retry_count` INT NOT NULL DEFAULT 0 COMMENT 'Consecutive execution/report failures',
|
||
`pending_report_state` VARCHAR(16) DEFAULT NULL COMMENT 'Retry this result only; do not rescan data',
|
||
`id` INT NOT NULL AUTO_INCREMENT,
|
||
`task_uuid` VARCHAR(36) NOT NULL COMMENT '中心任务身份(<b>唯一键</b>:重复指令复用本行与检查点,不另起一轮扫描)',
|
||
`attempt` INT NOT NULL DEFAULT 0 COMMENT '当前执行的派发尝试;更旧 attempt 的指令只吸收,不动检查点与已提交结论',
|
||
`consumer_app_key` VARCHAR(64) NOT NULL COMMENT '本应用消费身份(须与已验签身份逐字相等才收)',
|
||
`consumer_school_id` BIGINT NOT NULL COMMENT '本轮租户域:本地扫描按它限定行集,跨校指令拒收',
|
||
`form_uuid` VARCHAR(32) NOT NULL COMMENT '本轮范围的表单坐标(一行任务=一个 (消费方, 租户域, 表单))',
|
||
`form_version` INT NOT NULL COMMENT '中心已核验的版本(不从本地旧清单猜)',
|
||
`trigger_type` VARCHAR(16) DEFAULT NULL COMMENT 'SCHEDULE / MANUAL',
|
||
`window_start` DATETIME NOT NULL COMMENT '任务起点:本地 create_time 晚于它或为空的行<b>只报告、不退役</b>',
|
||
`total_rows` INT NOT NULL DEFAULT 0 COMMENT '中心清单总行数(完整性核对用)',
|
||
`total_pages` INT NOT NULL DEFAULT 0 COMMENT '中心清单确定总页',
|
||
`page_size` INT NOT NULL DEFAULT 200 COMMENT '两侧同页大小(上限 500):锁步比较才对得上',
|
||
`state` VARCHAR(16) NOT NULL DEFAULT 'QUEUED' COMMENT 'QUEUED/RUNNING/COMPLETED/PARTIAL/FAILED/CANCELLED',
|
||
`fc_cursor` VARCHAR(32) DEFAULT NULL COMMENT '中心清单游标(=水位,answer_uuid)',
|
||
`local_cursor` VARCHAR(32) DEFAULT NULL COMMENT '本地图像游标(=水位,answer_uuid)',
|
||
`watermark` VARCHAR(32) DEFAULT NULL COMMENT '两侧都已比较到的最大 answer_uuid:断线重启从这里续',
|
||
`fc_completed` TINYINT NOT NULL DEFAULT 0 COMMENT '中心清单是否读到底(多余行判定的前提之一)',
|
||
`local_completed` TINYINT NOT NULL DEFAULT 0 COMMENT '本地图像是否扫完(另一个前提)',
|
||
`pages_processed` INT NOT NULL DEFAULT 0 COMMENT '已推进的锁步轮数',
|
||
`scanned_rows` INT NOT NULL DEFAULT 0 COMMENT '比较过的答卷数',
|
||
`missing_repaired` INT NOT NULL DEFAULT 0 COMMENT '缺失修复 APPLIED 数(期望三元组全 null,只建未关联投影)',
|
||
`stale_repaired` INT NOT NULL DEFAULT 0 COMMENT '陈旧与同版错 hash 的修复 APPLIED 数(同一权威入口)',
|
||
`hash_conflicts` INT NOT NULL DEFAULT 0 COMMENT '同 revision 异 hash 的观察数(记录后才取中心当前值修复)',
|
||
`tombstones_repaired` INT NOT NULL DEFAULT 0 COMMENT '墓碑修复数(保留本地业务扩展列,不物理删)',
|
||
`local_ahead` INT NOT NULL DEFAULT 0 COMMENT '本地 revision 更高:向中心复核后只报告,禁止降级覆盖',
|
||
`deferred` INT NOT NULL DEFAULT 0 COMMENT '新鲜授权核验不可达/撤权/纪元不等而暂停的条目',
|
||
`extra_reported` INT NOT NULL DEFAULT 0 COMMENT '本地多出的行观察数(含期间新增与 createTime 未知,只报告)',
|
||
`extra_retired` INT NOT NULL DEFAULT 0 COMMENT '经中心签名缺席证明实际退役的行数',
|
||
`pending_extras_json` MEDIUMTEXT NOT NULL COMMENT '待缺席答复的多余行候选(含 create_time;<b>不含值文档</b>,有上限)',
|
||
`error_count` INT NOT NULL DEFAULT 0 COMMENT '错误条数',
|
||
`errors_json` MEDIUMTEXT NOT NULL COMMENT '错误明细(每条含 consumer/task/range/answer 四坐标,<b>敏感 values 永不进这里</b>)',
|
||
`reported_attempt` INT DEFAULT NULL COMMENT '已提交给中心的结果 attempt(同 attempt 不重复提交)',
|
||
`reported_state` VARCHAR(16) DEFAULT NULL COMMENT '已提交的结果状态',
|
||
`resumed` INT NOT NULL DEFAULT 0 COMMENT 'RUNNING 超租约后被重新领取的次数(这一轮断过几次)',
|
||
`lease_until` DATETIME DEFAULT NULL COMMENT '本地执行租约:超期才可被别的扫描线程领走续跑',
|
||
`next_retry_at` DATETIME DEFAULT NULL COMMENT '退避到点才再扫(扫描中断/回报不可达时写)',
|
||
`received_at` DATETIME NOT NULL COMMENT '指令落库时刻(接收端点 2xx 的依据就在这列)',
|
||
`started_at` DATETIME DEFAULT NULL COMMENT '首次开始执行时刻',
|
||
`finished_at` DATETIME DEFAULT NULL COMMENT '终态落定时刻',
|
||
`last_error_code` VARCHAR(32) DEFAULT NULL COMMENT '末次稳定码(GRANT_REVOKED/CANCELLED/MANIFEST_INCOMPLETE/…)',
|
||
`last_error` VARCHAR(500) DEFAULT NULL COMMENT '末次错误摘要(截断存)',
|
||
`create_by` VARCHAR(255) DEFAULT NULL,
|
||
`create_time` DATETIME DEFAULT NULL,
|
||
`update_by` VARCHAR(255) DEFAULT NULL,
|
||
`update_time` DATETIME DEFAULT NULL,
|
||
PRIMARY KEY (`id`),
|
||
UNIQUE KEY `uk_reconcile_work_task` (`task_uuid`),
|
||
KEY `idx_reconcile_work_scan` (`state`, `next_retry_at`),
|
||
KEY `idx_reconcile_work_consumer` (`consumer_app_key`, `consumer_school_id`, `id`)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
|
||
COMMENT='对账任务接收与检查点(TASK_3:接收与执行解耦、同 taskId 幂等复用、重启从 watermark 续页;不存值文档)';
|
||
|
||
-- 自验(执行后逐条核对):
|
||
-- SHOW CREATE TABLE answer_reconcile_work\G -- 应含 uk_reconcile_work_task(同 taskId 只一行)
|
||
-- SELECT COUNT(*) FROM information_schema.referential_constraints
|
||
-- WHERE table_name='answer_reconcile_work'; -- 必须 0 行(无物理外键)
|
||
-- SELECT COUNT(*) FROM information_schema.columns
|
||
-- WHERE table_schema=DATABASE() AND table_name='answer_reconcile_work'
|
||
-- AND column_name IN ('values_json','snapshot_json','context_token');
|
||
-- -- 必须 0 行(值文档与令牌不进对账检查点)
|