内规同步流程分析与排查方案

hgtp bizmgt -- 企业级制度管理系统 -> 合规图谱系统

1 -- 同步总览

内规同步并非一步完成,而是分三个独立阶段,由三个定时任务驱动,数据在不同表之间流转。任何一个阶段中断都会导致"同步停滞"。

Stage 1
拉取制度数据
Stage 2
转换为法规记录
Stage 3
同步ES/图谱
2 -- 三阶段详细流程
STEP 1
读取流水号
reg_increment
表id=1
STEP 2
调用制度接口
POST zd.url
Trace_Code=HGTP
STEP 3
解析XML响应
解析制度信息
附件base64解码
STEP 4
保存同步记录
hg_law_regulation
_sync_record
STEP 5
递归拉取
next_trace_id
有值则继续
关键逻辑: 递归拉取由 zd.mode 控制。当 mode 为空或 multiple 时,如果接口返回 next_trace_id,则递归调用自身继续拉取下一条。zd.limit 控制单次任务最大拉取次数。sync_status 初始为 0(未同步)。
sync_status = 0 (未同步)
STEP 1
查询待同步
sync_status=0|3
status=3, del=0
resp_code=000000
result_code=S
STEP 2
分组处理
按regs_id分组
取最新trace_id
STEP 3
新增/更新
写入law_regulation
_record表
type=2,source=3
STEP 4
附件处理
文件路径转换
DOC转HTML
STEP 5
更新状态
sync_status
→ 2(成功)
筛选条件极严格: 必须满足 del_int=0 + status=3(已入库) + resp_code=000000 + result_code=S + sync_status IN (0,3)。任何一个条件不满足,该条记录就不会被转换。
写入 law_regulation_record
enforceReg()
处理未生效法规使其生效
图库同步
GET /data/graph → data-service
ES同步
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.java Stage 1 定时任务
  • bizmgt/job/monitor/SyncRegsDataJobScheduler.java Stage 1 调度器 (00:00)
  • bizmgt/biz/QueryZdRegsBiz.java Stage 1 核心逻辑
  • bizmgt/configuration/ZdConfigurationProperties.java 制度系统配置 (zd.url/mode/limit)
  • bizmgt/job/monitor/UpdateRegsDataJob.java Stage 2 定时任务
  • bizmgt/job/monitor/UpdateRegsDataJobScheduler.java Stage 2 调度器 (每2h)
  • bizmgt/biz/UpdateZdRegsBiz.java Stage 2 核心逻辑
  • bizmgt/biz/LawRegulationRecordBiz.java Stage 2 法规记录CRUD
  • bizmgt/job/monitor/SyncDataJob.java Stage 3 定时任务
  • bizmgt/job/monitor/SyncJobScheduler.java Stage 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 -- 疑似问题点分析
高概率 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_codeerror_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 参考
-- 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;
-- 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;
-- 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');
-- 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 修复后等待自动重试即可。