内规同步流程分析与排查方案
hgtp bizmgt -- 企业级制度管理系统 -> 合规图谱系统
1 -- 同步总览
内规同步三阶段架构
内规同步并非一步完成,而是分三个独立阶段,由三个定时任务驱动,数据在不同表之间流转。任何一个阶段中断都会导致"同步停滞"。
Stage 1
拉取制度数据
Stage 2
转换为法规记录
Stage 3
同步ES/图谱
2 -- 三阶段详细流程
Stage 1: 从制度管理系统拉取数据 SyncRegsDataJob
STEP 1
读取流水号
reg_increment
表id=1
表id=1
→
STEP 2
调用制度接口
POST zd.url
Trace_Code=HGTP
Trace_Code=HGTP
→
STEP 3
解析XML响应
解析制度信息
附件base64解码
附件base64解码
→
STEP 4
保存同步记录
hg_law_regulation
_sync_record
_sync_record
→
STEP 5
递归拉取
next_trace_id
有值则继续
有值则继续
关键逻辑: 递归拉取由
zd.mode 控制。当 mode 为空或 multiple 时,如果接口返回 next_trace_id,则递归调用自身继续拉取下一条。zd.limit 控制单次任务最大拉取次数。sync_status 初始为 0(未同步)。
sync_status = 0 (未同步)
Stage 2: 转换为法规记录 UpdateRegsDataJob
STEP 1
查询待同步
sync_status=0|3
status=3, del=0
resp_code=000000
result_code=S
status=3, del=0
resp_code=000000
result_code=S
→
STEP 2
分组处理
按regs_id分组
取最新trace_id
取最新trace_id
→
STEP 3
新增/更新
写入law_regulation
_record表
type=2,source=3
_record表
type=2,source=3
→
STEP 4
附件处理
文件路径转换
DOC转HTML
DOC转HTML
→
STEP 5
更新状态
sync_status
→ 2(成功)
→ 2(成功)
筛选条件极严格: 必须满足
del_int=0 + status=3(已入库) + resp_code=000000 + result_code=S + sync_status IN (0,3)。任何一个条件不满足,该条记录就不会被转换。
写入 law_regulation_record
Stage 3: 同步至ES和图谱 SyncDataJob
enforceReg()
处理未生效法规使其生效
图库同步
GET
/data/graph → data-serviceES同步
GET
/data/sync?type=0 → data-service机构同步
POST
/org/insertOrg 3 -- 定时任务配置
| 定时任务 | Job 类 | Cron | 调度说明 | 初始化方式 | 状态 |
|---|---|---|---|---|---|
| Stage 1: 拉取制度 | SyncRegsDataJobSyncRegsDataJobScheduler |
0 0 0 * * ?每天 00:00 |
调用制度管理系统API拉取最新内规 | @PostConstruct | 自启动 |
| Stage 2: 转换法规 | UpdateRegsDataJobUpdateRegsDataJobScheduler |
0 0 0/2 * * ?每2小时 |
将同步记录转为法规记录表 | @PostConstruct | 自启动 |
| Stage 3: ES/图谱同步 | SyncDataJobSyncJobScheduler |
0 0 18 * * ?每天 18:00 |
同步ES索引、图数据库、机构数据 | @PostConstruct | 自启动 |
| 入库审批分发 | RegInnerSyncMonitorDataJobRegInnerSyncMonitorJobScheduler |
0 0 20 * * ?每天 20:00 |
对新增法规记录发起入库审批流程 | 手动调用 | 需Controller触发 |
| 内规入库监控 | RegEnterMonitorDataJobRegEnterMonitorJobScheduler |
-- | RegMaintainController.init()触发 | Controller init | 间接启动 |
4 -- 关键代码路径
核心类与方法
Stage 1 入口
QueryZdRegsBiz.syncRegsFromZd()调用
callZd() 发送HTTP请求regsProcess() 解析+保存递归
queryRegsFromZd()
Stage 2 入口
UpdateZdRegsBiz.updateLawRegulation()分页查询 sync_record (每页20条)
dataProcess() → lawRegulationProcess()新增/更新法规记录
Stage 3 入口
SyncDataJob.execute()enforceReg() 法规生效GET data-service 同步ES/图谱
入库审批入口
RegMaintainServiceImpl.launchTask()查24h内 sourceType=1 maintain=0 的记录
创建入库审批任务
关键文件路径一览
bizmgt/job/monitor/SyncRegsDataJob.javaStage 1 定时任务bizmgt/job/monitor/SyncRegsDataJobScheduler.javaStage 1 调度器 (00:00)bizmgt/biz/QueryZdRegsBiz.javaStage 1 核心逻辑bizmgt/configuration/ZdConfigurationProperties.java制度系统配置 (zd.url/mode/limit)bizmgt/job/monitor/UpdateRegsDataJob.javaStage 2 定时任务bizmgt/job/monitor/UpdateRegsDataJobScheduler.javaStage 2 调度器 (每2h)bizmgt/biz/UpdateZdRegsBiz.javaStage 2 核心逻辑bizmgt/biz/LawRegulationRecordBiz.javaStage 2 法规记录CRUDbizmgt/job/monitor/SyncDataJob.javaStage 3 定时任务bizmgt/job/monitor/SyncJobScheduler.javaStage 3 调度器 (18:00)bizmgt/service/impl/RegMaintainServiceImpl.java法规维护Service (2400+行)bizmgt/client/model/entity/reg/LawRegulationSyncRecord.java同步记录实体bizmgt/client/enums/SyncStatusEnum.java同步状态枚举 (0未同步/1同步中/2成功/3失败)
5 -- 疑似问题点分析
可能导致同步停滞27天的原因
高概率 Stage 1: 制度接口异常
QueryZdRegsBiz.callZd() 调用外部制度系统API失败(网络、认证、接口变更),catch后仅log不抛出,同步记录 result_code=E,Stage 2 筛选条件要求 result_code=S,导致整条链路断裂
高概率 Stage 1: 流水号问题
reg_increment 表 id=1 的 sequence_id 如果被设为无效值或制度系统已不再返回新数据(Trace_Id到头了),则每次拉取返回空/错误,同步就此停滞
中概率 Stage 2: 数据条件不满足
Stage 2 要求同时满足5个条件:
del_int=0, status=3, resp_code=000000, result_code=S, sync_status IN(0,3)。制度系统返回的 status 不是3(已入库)等状态异常会导致永远不被捡起
中概率 Stage 2: sync_status 卡死
Stage 2 处理前先将 sync_status 改为
1(同步中),如果中途服务重启/OOM,status 永远是1,不在查询条件 IN(0,3) 中,这批数据将永远不会被处理
低概率 Quartz调度器异常
Quartz 使用
@DisallowConcurrentExecution,如果上一次执行卡住未返回(如HTTP超时等),后续调度将被阻塞。检查Quartz表 QRTZ_TRIGGERS 状态
低概率 服务未正常启动
bizmgt 服务重启后
@PostConstruct 如果抛异常,调度器可能没有正常注册。虽然3个核心scheduler都有 PostConstruct,但需检查启动日志
6 -- 生产排查方案
| 步骤 | 排查项 | 操作方法 | 预期结论 |
|---|---|---|---|
| Step 1 | 确认断点在哪个Stage |
查询 hg_law_regulation_sync_record 表最近记录的 create_time如果27天前就没有新记录 -> Stage 1 断了 如果有新记录但 sync_status != 2 -> Stage 2 断了 |
定位问题阶段 |
| Step 2 | 检查 Stage 1 拉取状态 |
查最近的 sync_record 的 result_code 和 error_msg查 reg_increment id=1 的 sequence_id检查是否有大量 result_code=E 的记录 |
确认接口是否通畅 |
| Step 3 | 检查 Stage 2 转换状态 |
统计 sync_record 中 sync_status 分布 重点关注 sync_status=1(卡死) 和 status!=3 |
确认是否有数据卡在中间状态 |
| Step 4 | 检查 Quartz 调度器 |
查 QRTZ_TRIGGERS 表中3个job的trigger状态查服务启动日志中 scheduler 注册信息 WAITING=正常, BLOCKED=卡死, ERROR=异常 |
确认定时任务是否正常调度 |
| Step 5 | 检查应用日志 |
搜索关键词: [HGTP]-同步法规数据开始调用企业级制度管理系统同步法规制度失败[HGTP]-[更新法规制度]-没有要更新的数据确认最后成功执行时间和失败原因 |
获取具体错误信息 |
| Step 6 | 检查外部制度系统 |
确认 zd.url 配置的接口是否可达手动调用测试: POST zd.url, params: Trace_Code=HGTP 排除网络/防火墙/接口变更等问题 |
确认外部依赖正常 |
| Step 7 | 手动触发同步验证 |
调用 RegMaintainController 的 /reg/syncRegsFromZd 接口观察返回结果和日志 确认修复后同步链路是否恢复 |
验证修复效果 |
7 -- 排查 SQL 参考
Step 1: 定位断点阶段
-- 1. 查看同步记录表最新记录时间 SELECT MAX(create_time) AS last_sync_time, COUNT(*) AS total_records FROM hg_law_regulation_sync_record WHERE deleted = 0; -- 2. 查看最近30天同步记录分布 SELECT DATE(create_time) AS sync_date, COUNT(*) AS record_count, SUM(CASE WHEN result_code = 'S' THEN 1 ELSE 0 END) AS success_count, SUM(CASE WHEN result_code = 'E' THEN 1 ELSE 0 END) AS error_count FROM hg_law_regulation_sync_record WHERE deleted = 0 AND create_time >= DATE_SUB(NOW(), INTERVAL 30 DAY) GROUP BY DATE(create_time) ORDER BY sync_date DESC;
Step 2: 检查 Stage 1 状态
-- 3. 查看当前流水号 SELECT * FROM reg_increment WHERE id = 1; -- 4. 查看最近的错误记录 SELECT id, trace_id, regs_id, regs_name, result_code, error_msg, resp_code, sync_status, status, create_time FROM hg_law_regulation_sync_record WHERE deleted = 0 ORDER BY create_time DESC LIMIT 20;
Step 3: 检查 Stage 2 状态
-- 5. sync_status 分布统计 SELECT sync_status, CASE sync_status WHEN '0' THEN '未同步' WHEN '1' THEN '同步中(可能卡死)' WHEN '2' THEN '同步成功' WHEN '3' THEN '同步失败' END AS status_desc, COUNT(*) AS cnt FROM hg_law_regulation_sync_record WHERE deleted = 0 GROUP BY sync_status; -- 6. 检查卡在"同步中"的记录 (sync_status=1 可能是服务重启导致) SELECT id, trace_id, regs_id, regs_name, sync_status, create_time, update_time FROM hg_law_regulation_sync_record WHERE deleted = 0 AND sync_status = '1' ORDER BY create_time DESC; -- 7. 检查符合 Stage 2 处理条件但未被处理的记录 SELECT COUNT(*) AS pending_count FROM hg_law_regulation_sync_record WHERE deleted = 0 AND del_int = '0' AND status = 3 AND resp_code = '000000' AND result_code = 'S' AND sync_status IN ('0', '3');
Step 4: 检查 Quartz 调度器
-- 8. 检查 Quartz trigger 状态 SELECT TRIGGER_NAME, TRIGGER_STATE, FROM_UNIXTIME(PREV_FIRE_TIME/1000) AS prev_fire, FROM_UNIXTIME(NEXT_FIRE_TIME/1000) AS next_fire FROM QRTZ_TRIGGERS WHERE TRIGGER_NAME IN ( 'sync-reg-data-job-trigger', 'update-reg-data-job-trigger', 'sync-data-job-trigger' ); -- 9. 检查最新法规记录时间 (确认 Stage 2 输出) SELECT MAX(create_time) AS last_record_time FROM hg_law_regulation_record WHERE type = 2 AND source_type = 3; -- 10. 如需修复卡死数据 (sync_status=1 -> 3 让它重试) -- UPDATE hg_law_regulation_sync_record -- SET sync_status = '3' -- WHERE sync_status = '1' AND deleted = 0;
排查优先级建议: 先执行 SQL 1-4 确定断点在哪个阶段,再针对性检查日志。如果 Stage 1 最后一条记录在27天前且
result_code=E,大概率是外部制度系统接口出了问题(网络/鉴权/接口变更)。如果 Stage 1 有数据但 sync_status 全卡在1,说明 Stage 2 处理时服务异常重启过,执行 SQL 10 修复后等待自动重试即可。