728x90

개요

1편에서 배치에 대해 살펴보았고 이제 내가 하는 프로젝트에 배치를 적용해볼 예정이다. 

 

일단 나는 SSE 알림 기능을 구현했는데, 일정 기간동안 읽지 않은 알림이 있다면 사용자에게 "읽지 않은 알림이 있습니다." 라는 문구를 띄어줄려고 한다. 주기적인 스케줄을 가지고 필요한 알림을 처리하기 위한 기술이 필요했다. 그래서 주기적인 schedule 에 따라 Spring Batch를 통해서 필요 데이터를 reading, 알람을 보내는 기능을 구현하기로 했고 알람은 SSE를 사용하기로 했다.

 

사용자가 접근하지 않는 시간대인 매일 자정에 매번 실행해서 7일동안 읽지않은 알림이 존재할 경우 알림을 보내는 역할을 할 것이다.

 

 


설정

 

build.gradle

// spring batch
implementation 'org.springframework.boot:spring-boot-starter-batch'

batch 의존성 추가

 

 

application.yml

spring:
  application:
    name: {name}

  batch:
    jdbc:
      initialize-schema: always #batch 스키마 자동 생성
    job:
      enabled: false #시작과 동시에 실해되는건 방지

 

 

 

Cofing.java

@Configuration
@EnableBatchProcessing
@Slf4j
@RequiredArgsConstructor
public class NotificationBatchConfig {

    private final JobRepository jobRepository;
    private final PlatformTransactionManager platformTransactionManager;
    private final NotificationRepository notificationRepository;

    // 배치 작업의 전체 실행
    @Bean
    public Job deleteNotificationsJob(Step deleteUnreadNotificationsStep) {
        log.info(">>> Creating deleteNotificationsJob");
        return new JobBuilder("deleteNotificationsJob", jobRepository)
                .start(deleteUnreadNotificationsStep)
                .build();
    }

    // 배치 작업 내 실행되는 개별 처리
    @Bean
    public Step deleteUnreadNotificationsStep() {
        log.info(">>> Creating deleteUnreadNotificationsStep");
        return new StepBuilder("deleteUnreadNotificationsStep", jobRepository)
                .tasklet(deleteUnreadNotificationsTasklet(), platformTransactionManager)
                .build();
    }

    // 10분 이상 읽지 않은 알림 삭제
    @Bean
    public Tasklet deleteUnreadNotificationsTasklet() {
        return (contribution, chunkContext) -> {
            LocalDateTime cutoffTime = LocalDateTime.now().minusMinutes(10);
            List<Notification> notificationsToDelete = notificationRepository.findByIsReadAndCreatedAtBefore(false, cutoffTime);
            notificationRepository.deleteAll(notificationsToDelete);
            log.info("Deleted unread notifications older than 10 minutes");
            return RepeatStatus.FINISHED;
        };
    }
}

 

 

Tasklet

  • 일반적인 Component와 비슷한 개념, 개발자가 지정한 커스텀한 기능을 위한 단위
  • 개발자가 이 STEP에서 하고 싶은 내용을 자유롭게 만들 수 있다.

 

 

BatchScheduler.java

@Component
@Slf4j
@RequiredArgsConstructor
public class NotificationBatchScheduler {

    private final JobLauncher jobLauncher; // 정의된 job 을 주기적 실행
    private final Job deleteNotificationsJob;

    @Scheduled(cron="0 0 12 * * *", zone = "Asia/Seoul") // 매일 자정에 실행
    public void runDeleteUnreadNotificationsJob() {
        try {
            jobLauncher.run(deleteNotificationsJob, new JobParametersBuilder()
                    .addLong("timestamp", System.currentTimeMillis())
                    .toJobParameters());
            log.info("Notification deletion job executed successfully.");
        } catch (Exception e) {
            log.error("Failed to execute notification deletion job", e);
        }
    }
}

 

jobLauncher.run()메서드는 첫번째 파라미터로 Job, 두번째 파라미터로 Job Parameter를 받고있다.
Job Parameter의 역할은 반복해서 실행되는 Job의 유일한 ID이다.

Launcher 가 어떤 배치 작업(Job)을 실행할 지에 대해 작성한다. 

Job은 어떤 데이터들을 통해서 어떤 작업을 실행할 지, 실행 순서 등에 대한 내용(Step)을 담고 있어야 한다.

 

 

Scheduler

  • batch를 수행하기 위한 Scheduler를 파일에 구성(매일 자정에 실행)
Spring Batch는 Batch Job을 관리하지만 `Job`을 구동하거나 실행시키는 기능은 지원하고 있지않다.
Spring에서 Batch Job을 실행시키기 위해서는 `Quartz, Scheduler`와 같은 전용 Scheduler를 사용해야한다.
728x90

+ Recent posts