1. 背景与需求
在系统中,我们需要处理案件的推送流程,包括以下主要阶段:
- 报案:向外部系统推送案件的报案信息。
- 影像件推送:推送影像件信息。
- 理算推送:推送理算信息。
案件的状态需要按照顺序流转,流程分为以下几步:
- 初始化 -> 报案成功 -> 影像件推送成功 -> 保司影像件上传成功 -> 理算推送成功 -> 保司理算成功。
1.1 需求痛点
- 同步处理性能问题:每个阶段通过轮询处理,效率低,无法充分利用系统资源。
- 逻辑耦合度高:状态判断逻辑集中在一个模块中,不易扩展。
- 缺乏动态触发机制:影像件推送完成后需要等待保司的回调,但原始模型中没有合适的触发机制。
- 扩展性差:增加新的状态或流程需要修改大量代码。
- 内存风险:一次性查询过多数据可能占用大量内存,影响系统稳定性。
2. 原始推送模型
2.1 原始模型设计
原始模型采用 while
循环与定时任务相结合的方式,通过状态判断批量处理案件:
流程逻辑
- 定时查询数据库,获取 初始化 状态的案件,批量执行 报案推送。
- 查询 报案成功 状态的案件,批量执行 影像件推送。
- 查询 影像件推送成功 状态的案件,等待保司的回调完成后,执行 理算推送。
核心代码逻辑
while (true) {
// 查询初始化案件并推送报案
List<Task> initTasks = fetchTasksByStatus("初始化");
pushRegist(initTasks);
// 查询报案成功案件并推送影像件
List<Task> registSuccessTasks = fetchTasksByStatus("报案成功");
pushImage(registSuccessTasks);
// 查询影像件推送成功案件并推送理算
List<Task> imageSuccessTasks = fetchTasksByStatus("影像件推送成功");
pushClaim(imageSuccessTasks);
}
2.2 原始模型的问题
- 轮询效率低:
while
循环不断查询数据库,消耗资源,增加数据库压力。
- 同步阻塞:
- 所有任务同步执行,不能充分利用多线程并发能力。
- 缺乏动态触发机制:
- 影像件推送完成后无法主动监听保司的回调事件。
- 难以扩展:
- 状态和逻辑耦合度高,新增状态或流程需要修改现有代码。
- 内存占用问题:
- 一次性查询过多数据可能导致内存不足,甚至引发 OOM(OutOfMemoryError)。
3. 优化后的推送模型
针对上述问题,优化后的模型采用 分段式任务处理 + 事件驱动机制,并通过 分页查询 和 流式处理 优化数据加载方式。
3.1 优化模型设计
第一段任务
- 处理 报案推送 和 影像件推送。
- 通过定时任务批量处理,完成状态流转。
第二段任务
- 基于事件驱动机制,监听保司的回调事件。
- 动态触发 理算推送 流程。
3.2 优化模型的核心架构
任务调度器
- 定时调度,查询数据库中各阶段的任务,并提交给线程池处理。
任务状态机
- 每个阶段对应一个处理模块(如报案推送、影像件推送、理算推送)。
- 状态独立实现,逻辑解耦。
事件驱动机制
- 使用 Spring 事件监听器监听保司的回调事件,动态触发理算推送。
数据查询优化
- 分页查询:限制每次查询数据量。
- 流式处理:逐条读取数据,避免一次性加载过多数据。
3.3 优化后的任务处理流程
第一段任务
public void executeFirstSegment(Task task) {
if ("初始化".equals(task.getStatus())) {
taskManager.processTask(task, "报案成功");
}
if ("报案成功".equals(task.getStatus())) {
taskManager.processTask(task, "影像件推送成功");
}
}
第二段任务
@EventListener
public void handleImageUploadSuccessEvent(ImageUploadSuccessEvent event) {
String caseId = event.getCaseId();
Task task = taskManager.getTaskById(caseId);
if (task != null && "保司影像件上传成功".equals(task.getStatus())) {
taskManager.processTask(task, "理算推送成功");
}
}
数据查询优化
分页查询:
public List<Task> fetchTasksByStatus(String status, int page, int size) {
return jdbcTemplate.query(
"SELECT * FROM tasks WHERE status = ? LIMIT ?, ?",
new Object[]{status, page * size, size},
new BeanPropertyRowMapper<>(Task.class)
);
}
流式处理:
jdbcTemplate.query(
"SELECT * FROM tasks WHERE status = ?",
new Object[]{status},
rs -> {
while (rs.next()) {
Task task = mapRowToTask(rs);
threadPool.execute(() -> processTask(task));
}
}
);
3.4 优化模型的特点
-
解耦逻辑:
- 每个状态独立实现,逻辑清晰。
- 状态流转由任务管理器统一管理,避免嵌套复杂判断。
-
性能提升:
- 第一段任务批量处理,利用线程池并发执行。
- 第二段任务通过事件监听器触发,避免轮询消耗。
-
动态响应:
- 保司的回调通过事件触发,理算推送任务即时响应。
-
内存优化:
- 分页查询和流式处理,降低内存占用。
4. 模型对比
对比项 | 原始模型 | 优化模型 |
---|---|---|
任务处理方式 | 同步轮询 | 分段式任务 + 异步事件 |
逻辑解耦 | 状态判断集中,耦合度高 | 每个阶段独立实现,逻辑解耦 |
性能 | 单线程处理,数据库压力大 | 线程池并发处理,减少资源消耗 |
动态触发 | 不支持动态触发,需要轮询数据库 | 基于事件机制,支持动态触发 |
内存优化 | 一次性加载所有数据,可能导致内存不足 | 分页查询 + 流式处理,降低内存使用 |
扩展性 | 增加新状态需要修改核心逻辑 | 新增状态只需实现对应的处理逻辑 |
5. 总结
优化后的模型优势
- 性能提升:线程池并发处理批量任务,提升推送效率。
- 逻辑清晰:各阶段职责单一,降低耦合度,易于维护。
- 动态响应:事件驱动机制实现动态任务触发,无需频繁轮询。
- 内存稳定性:分批处理和流式查询减少内存占用,提升系统稳定性。
适用场景
- 复杂任务流转场景。
- 需要与外部系统交互并等待回调的场景。
- 对性能和扩展性有较高要求的场景。
优化后的推送模型不仅解决了原始模型的痛点,还为系统的扩展和高效运行提供了可靠的基础。