개발/Spring Batch

[Spring Batch] 환율 정보 API 를 간단한 배치 스케줄러 추가 - 예제편

seopport 2023. 11. 24. 22:00
728x90
반응형

들어가기 앞서

지난 시간 간단하게 만들었던 Batch에 Scheduler(스케줄러)와 Log를 추가한 내용을 작성한 글입니다. 스프링 배치를 사용하면서 언제, 어떻게 호출하고 실행시킬지에 대한 고민을 해야 합니다. 배치는 일괄적인 처리를 위해서 단독으로 사용되기도 하지만 실제 업무에서는 스케줄러와 같이 사용되는 것을 자주 볼 수 있습니다. 그렇다면 스케줄러 이외에 어떤 경우에 배치를 호출할까요? 클라이언트가 특정 URL 주소를 접근하게 되었을 때에도 사용합니다. 코드 내 Controller에서 해당 Service를 호출하고 Service에 특정 Batch를 호출하여 사용합니다.

 

Spring Batch Logo
Spring Batch Logo

 

배치(Batch)라고 떠올리실 때 '특정 시간에 특정 작업을 하는 것'이라고 생각하시면 안 됩니다. 배치는 데이터들을 일괄적으로 처리하기 위한 작업이며, 특정 일자나 특정 시간에 맞춰 작업을 하는 것은 스케줄러(Scheduler)입니다.

 

배치를 실행하고 특정 테이블(A)에 영향을 미치게 된다면, 특정 테이블(A) 에 걸려있는 트리거(Trigger)가 실행되고 예상치 못한 결과를 가져오기도 합니다. 배치를 사용하는 것은 일관성을 보장해 주지만 다른 영향도를 분석하고 사용하는 것이 중요합니다.

 

서론이 조금 길었네요. 본론으로 바로 가보겠습니다.

 

2023.11.23 - [개발/Spring & Spring Boot & Spring Batch] - [Spring Batch] 환율 정보 Open API를 활용한 간단한 배치 만들기 - 예제 편

 

[Spring Batch] 환율 정보 Open API를 활용한 간단한 배치 만들기 - 예제편

들어가기에 앞서 이전 블로그 글에 아래와 같은 글을 남겼습니다. 2023.11.15 - [개발/Spring & SpringBoot] - [Spring Boot] 대용량 데이터 처리를 위해 Batch를 알아보자 - 이론 편 [Spring Boot] 대용량 데이터 처

seodeveloper.tistory.com

 

ExchangeBatchApplication.java

메인 함수가 있는 클래스 파일입니다. 

 

@EnableScheduling

스프링 스케줄러(Scheduler)를 사용하기 위해, Spring Boot 실행파일에 @EnableScheduling를 선언하였습니다.

 

ExchangeBatchApplication.java 전체 코드

package com.main.exchangeBatch;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@EnableScheduling
public class ExchangeBatchApplication {

	public static void main(String[] args) {
		// 스프링 애플리케이션을 실행합니다.
		SpringApplication.run(ExchangeBatchApplication.class, args);
	}
}

 

 

ExchageBatchScheduler.java

@Scheduled(cron = "0/10 * * * * *")

테스트를 위해 배치가 10초마다 발생되도록 설정하였습니다.

 

크론(cron) 표현식 정리

  • 스케줄러 (Scheduler) 시간을 세팅할 때 사용됩니다.
  • 필드는 총 7개이며, 연도는 생략이 가능합니다. 

cron 표현식
cron 표현식

위 이미지에서 맨 마지막인 연도는 생략이 되었습니다.

 

cron에서 사용하는 특수문자

○  * : 모든 값을 뜻합니다.

○  ? : 특정한 값이 없음을 뜻합니다. 

○  - : 범위를 뜻합니다. 

 , : 특별한 값일 때만 동작 

  / : 시작시간 / 단위

 L : 일에서 사용하면 마지막 일, 요일에서는 마지막 요일(토요일)

 W : 가장 가까운 평일

 # : 몇째 주의 무슨 요일을 표현 

 

@Scheduled(cron = "0/10 * * * * *") // 10초
public void runJob() throws Exception {
    JobParameters parameters = new JobParametersBuilder()
            .addString("jobName", "exchangeJob" + System.currentTimeMillis())
            .toJobParameters();
    // add parameters as needed
    jobLauncher.run(job, parameters);
}

 

parameters의 유무

코드에서 parameters를 넘겨주는 코드를 발견할 수 있습니다.

addString으로 값을 넘겨주지 않고 아무것도 안 해도 되지 않을까 싶어 아래와 같은 코드를 작성을 해서 테스트해 보았습니다.

@Scheduled(cron = "0/10 * * * * *") // 10초
public void runJob() throws Exception {
    JobParameters parameters = new JobParametersBuilder().toJobParameters();
    jobLauncher.run(job, parameters);
}

 

결과는 어떻게 나왔을까요?

Step already complete or not restartable, so no action to execute: StepExecution: id=1, version=3, name=step, status=COMPLETED, exitStatus=COMPLETED, readCount=0, filterCount=0, writeCount=0 readSkipCount=0, writeSkipCount=0, processSkipCount=0, commitCount=1, rollbackCount=0, exitDescription=

 

'Step 이 이미 완료되었거나 재시작이 가능하지 않기 때문에 Step 실행(StepExecution)은 수행되지 않는다'

 

결론적으로 오류는 아니며, 정상적으로 실행은 되었지만 수행이 되지 않았습니다.

 

JobInstance를 식별하는 JobParameter

JobInstance를 고유하게 식별할 수 있게 하기 위해선 외부(또는 내부)로부터 받은 파라미터 값이 필요합니다. 제 코드에서는 실행시점을 나타내는 값 (System.currentTimeMillis()) 을 이용하여 JobInstance를 생성합니다.

 

ExchangeBatchScheduler.java 전체 코드

package com.main.exchangeBatch.scheduler;

import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class ExchangeBatchScheduler {

    @Autowired
    private JobLauncher jobLauncher;

    @Autowired
    private Job job;

    @Scheduled(cron = "0/10 * * * * *") // 10초
    public void runJob() throws Exception {
        JobParameters parameters = new JobParametersBuilder()
                .addString("jobName", "exchangeJob" + System.currentTimeMillis())
                .toJobParameters();
        // add parameters as needed
        jobLauncher.run(job, parameters);
    }
}

 

로그(Log)

System.out.println을 사용한 것을 log.info로 수정하였습니다.

 

처음 자바를 사용해서 개발을 할 때 작성하는 것은 System.out.println("Hello world!");입니다. 하지만 실제 업무에서 운영 중인 코드를 보면 System.out.println()가 적혀있는 곳을 확인하기 어렵습니다. (필자는 반드시 다 지우려는 편입니다.)

 

Log와 System.out.println 에 대한 차이점은 번역하고 싶은 글이 있어 따로 정리할 예정이며, 아래 인용글은 좋은 내용이 적혀있어 공유드립니다. 

 

한 번 요청 시 5000명의 사용자를 요청하고, 처리 과정에서 응답시간이 20초 걸리는 사이트가 있는데, 원인을 알아보니 5000명의 정보를 다 System.out.println()으로 처리하고 있던 것이다. 이는 System.out.println()을 줄임으로써 응답시간이 6초까지 줄었다.
 
- 이상민, 자바 성능 튜닝이야기, 인사이트, 2013

 

 

@Slf4j

@Slf4j는 롬복(Lombok) 어노테이션 중 하나로, SLF4J(Logger Facade for Java)를 사용하기 위한 로거를 자동으로 생성합니다. SLF4J는 Java 어플리케이션에서 로깅을 위한 추상화를 제공하며, 실제로 사용할 로깅 구현은 클래스패스에 존재하는 로깅 프레임워크에 의해 결정됩니다

 

ExchangeBatch.java

package com.main.exchangeBatch.batch;

... 생략
import lombok.extern.slf4j.Slf4j;


@Slf4j
@Configuration
public class ExchangeBatch {
    
    ... 생략
    
    @Bean
    public Tasklet tasklet(){
        return ((contribution, chunkContext) -> {
            List<ExchangeDto> exchangeDtoList = exchangeUtils.getExchangeDataAsDtoList();

            for (ExchangeDto exchangeDto : exchangeDtoList) {
                log.info("통화 : " + exchangeDto.getCur_nm());
                log.info("환율 : " + exchangeDto.getDeal_bas_r());
                // 추가적인 필드가 있다면 출력 또는 활용
            }
            return RepeatStatus.FINISHED;
        });
    }
}

 

 

실행 결과

배치 실행 결과
배치 실행 결과

 

Github 링크

https://github.com/SeoYounSeok/exchangeBatch.git

 

GitHub - SeoYounSeok/exchangeBatch: Spring Batch Project (Spring Batch, Open API)

Spring Batch Project (Spring Batch, Open API). Contribute to SeoYounSeok/exchangeBatch development by creating an account on GitHub.

github.com

 

참고 사이트

 

SLF4J

 

SLF4J

Simple Logging Facade for Java (SLF4J) The Simple Logging Facade for Java (SLF4J) serves as a simple facade or abstraction for various logging frameworks (e.g. java.util.logging, logback, log4j) allowing the end user to plug in the desired logging framewor

www.slf4j.org

 

배워가는 블로거:티스토리

 

[Cron] 크론(cron) 표현식 정리

■ Cron (크론) cron이란? 유닉스 계열의 잡 스케줄러 ● Cron 표현식 - 필드 Cron 스케줄러의 정규 표현식입니다. 7개의 각 필드로 구성되어 있으며, 각 필드의 내용은 아래와 같습니다. 자세한 설명은

zamezzz.tistory.com

 

노트북을 열고. 블로그

 

[spring boot batch] 3. 배치실행의 모든기록. 메타테이블

1. 메타(Meta)테이블, 존재의 이유. 이전 장에서 우리는 배치를 실행시키기 위한 총 9개의 테이블을 생성하였습니다. 사실 아주 간편하게 코드로만 배치프로세서를 구현할 줄 알았지 Batch프로세스

ahndy84.tistory.com

 

728x90
반응형