ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

[063][调度模块]事件驱动的日志记录与高效查询体系

[063][调度模块]事件驱动的日志记录与高效查询体系 [063][调度模块]事件驱动的日志记录与高效查询体系本文章代码: gitee , gitcode , github1. 事件驱动架构解耦调度与日志任务状态变更时ScheduleTaskManager发布ChangeStatusEventJobLogEventConsumer异步消费需配置Async。Slf4jComponentRequiredArgsConstructorpublicclassJobLogEventConsumerimplementsChangeStatusEventConsumer{privatefinalJobLogRepositoryjobLogRepository;privatefinalJobRepositoryjobRepository;OverrideAsync// ✅ 异步执行不阻塞主调度线程Transactional(propagationPropagation.REQUIRES_NEW)// ✅ 独立事务不受业务回滚影响publicvoidconsumer(ChangeStatusEventevent){TaskRuntimeDataruntimeDataevent.taskRuntimeData();jobRepository.findByTaskCode(runtimeData.taskCode()).ifPresentOrElse(task-{JobLogEntitylognewJobLogEntity();log.setJob(task);log.setTaskStatus(runtimeData.taskStatus());log.setLotNo(runtimeData.lotNo());log.setTotalCount(runtimeData.totalCount());log.setTotalFailureCount(runtimeData.totalFailureCount());log.setStartTime(runtimeData.startTime());log.setEndTime(runtimeData.endTime());// 异常信息智能截取ThrowablethrowableruntimeData.throwable();if(throwable!null){log.setHasError(YesNoEnum.Y);log.setMessage(StringUtils.substring(ExceptionUtils.getSelfStackTrace(throwable),0,500));}else{log.setHasError(YesNoEnum.N);log.setMessage(runtimeData.message());}jobLogRepository.save(log);},()-log.warn(任务不存在无法记录日志taskCode{},runtimeData.taskCode()));}}技术亮点异步独立事务日志写入不影响调度性能且即使主业务事务回滚日志依然留存。异常堆栈裁剪500 字符限制防止数据截断异常同时保留关键堆栈信息。空值友好使用ifPresentOrElse优雅处理任务不存在的情况。2. 日志查询的规格模式组合JobLogQuery支持多条件动态查询包括关联表JobEntity字段。publicclassJobLogSpecification{// 关联查询示例通过 leftJoin 连接 JobEntitypublicstaticSpecificationJobLogEntitytaskCodeEqual(StringtaskCode){return(root,query,cb)-{JoinJobLogEntity,JobEntityjobJoinleftJoin(root,job);returnJobSpecification.taskCodeEqual(jobJoin,taskCode,cb);};}// 时间范围查询publicstaticPredicatecreatedAtBetween(PathJobLogEntitypath,Instantstart,Instantend,CriteriaBuildercb){Predicatepredicatecb.conjunction();if(start!null){predicatecb.and(predicate,cb.greaterThanOrEqualTo(path.get(createdAt),start));}if(end!null){predicatecb.and(predicate,cb.lessThanOrEqualTo(path.get(createdAt),end));}returnpredicate;}}技术亮点类型安全使用 JPA 元模型Metamodel或字符串常量避免硬编码。可组合性每个条件都是独立的Specification可灵活组合复用。3. VO 组装与关联数据补充JobLogVO在转换时额外填充任务标识字段避免前端额外请求。DatapublicclassJobLogVOextendsBaseVO{// 日志自身字段privateTaskStatusEnumtaskStatus;privateStringlotNo;privateInstantcreatedAt;// ... 其他日志字段// 关联任务冗余字段非数据库字段用于展示privateStringtaskCode;privateStringclassSimpleName;publicstaticJobLogVOof(JobLogEntityentity){JobLogVOvonewJobLogVO();BeanUtils.copyProperties(entity,vo);JobEntityjobentity.getJob();if(job!null){vo.setTaskCode(job.getTaskCode());vo.setClassSimpleName(job.getClassSimpleName());}returnvo;}}设计权衡优点一次查询返回完整信息减少网络往返。注意若JobEntity中关联数据较大如metadata含大量 JSON不建议全部复制只取必要字段。4. 日志分页查询接口RestControllerRequestMapping(/api/job-log)RequiredArgsConstructorpublicclassJobLogEndpoint{privatefinalJobLogServicejobLogService;GetMapping(page)publicResponseEntityPagedModelJobLogVOfindPage(JobLogQueryquery,Pageablepageable){PageJobLogEntitypagejobLogService.find(query,pageable);returnResponseEntity.ok(newPagedModel(page.map(JobLogVO::of)));}}技术亮点Spring Data 集成Pageable自动解析分页参数PagedModel封装分页元数据。VO 映射page.map(JobLogVO::of)流式转换代码简洁。
返回列表