오늘은 Spring Batch 공식 문서를 열심히 뜯어본 날입니다.
Spring Batch JobExeuctuionListener라는 객체도 존재한다는 것을 알 수 있었는데
이 객체는 쉽게 말하면 Job이 실행되는 생명 주기를 관리하는 객체입니다.
기존에는 스케쥴러와 서비스 등에 로그 찍는게 분산이 되어있었는데요.
차라리 JobExecutionListener를 사용해서 로깅에 대한 책임을 얘한테만 주는 게 낫겠다는 생각이 들었습니다.
이게 더 표준적인 방법이라고 나와있기도 했고요.
적용을 한 결과
crawlingService는 단순히 Job의 실행만 책임지게 되었고, 스케쥴러도 스케쥴링만 책임지게 되었습니다.
Job의 로깅 및 성공과 실패에 대한 책임을 RssCrawlingJobListener한테 몰 수 있어서 매우 좋은 적용이었던거 같습니다.
@Slf4j
@Component
@RequiredArgsConstructor
public class RssCrawlingJobListener implements JobExecutionListener {
private final CrawlingHistoryRepository crawlingHistoryRepository;
private final WebhookNotificationService webhookNotificationService;
@Override
@Transactional
public void beforeJob(JobExecution jobExecution) {
Long jobExecutionId = jobExecution.getId();
log.info("RSS crawling job started: jobExecutionId={}", jobExecutionId);
CrawlingHistory history = CrawlingHistory.createStarted(jobExecutionId);
crawlingHistoryRepository.save(history);
}
@Override
@Transactional
public void afterJob(JobExecution jobExecution) {
Long jobExecutionId = jobExecution.getId();
BatchStatus batchStatus = jobExecution.getStatus();
CrawlingHistory history = crawlingHistoryRepository
.findByJobExecutionId(jobExecutionId)
.orElseThrow(() -> new IllegalStateException(
"CrawlingHistory not found for jobExecutionId: " + jobExecutionId));
if (batchStatus == BatchStatus.COMPLETED) {
handleJobSuccess(history, jobExecution);
} else {
handleJobFailure(history, jobExecution, "Job failed with status: " + batchStatus);
}
}
/**
* Job 성공 처리
*/
private void handleJobSuccess(CrawlingHistory history, JobExecution jobExecution) {
StepExecution stepExecution = jobExecution.getStepExecutions().iterator().next();
int readCount = (int) stepExecution.getReadCount();
int writeCount = (int) stepExecution.getWriteCount();
int skipCount = (int) stepExecution.getSkipCount();
history.complete(readCount, writeCount, skipCount);
crawlingHistoryRepository.save(history);
log.info("RSS crawling completed successfully: " +
"total={}, success={}, failed={}",
readCount, writeCount, skipCount);
}
/**
* Job 실패 처리
*/
private void handleJobFailure(CrawlingHistory history, JobExecution jobExecution, String errorMessage) {
history.fail(errorMessage);
crawlingHistoryRepository.save(history);
log.error("RSS crawling failed: {}", errorMessage);
// 실패 알림 전송
Map<String, Object> context = new HashMap<>();
context.put("errorMessage", errorMessage);
context.put("timestamp", LocalDateTime.now());
context.put("jobExecutionId", jobExecution.getId());
webhookNotificationService.sendCrawlingFailureNotification(context);
}
}
감사합니다.
'프로젝트 > Techfork' 카테고리의 다른 글
| [26/01/06] 오늘의 개발일지 - AsyncItemProcessor의 도입과 Spring Batch 메타데이터 활용 (0) | 2026.01.07 |
|---|---|
| [26/01/05] 오늘의 개발 일지 - Resilience4j 도입 (1) | 2026.01.06 |
| [25/01/02] 오늘의 개발 일지 - RSS 크롤링 성능 및 안정성 개선 (0) | 2026.01.03 |
| [26/01/01] 오늘의 개발 일지 - OCI 서버 배포 완료 (0) | 2026.01.01 |
| [25/12/31] 오늘의 개발 일지 - Oracle Cloud Infrastructure 가입! (0) | 2026.01.01 |