본문 바로가기

개발/02-1.Spring Batch

[SpringBatch, DEVOCEAN] Week10 (EZ하게) 스프링배치 플로우 컨트롤 하기

배경 : 스프링배치 10주차 과제 를 수행하기 위한  정리를 진행함.

 

참고 :

1.10주차 교재

(아래 글은 한국 스프링 사용자 모임(KSUG)에서 진행된 스프링 배치 스터디 내용을 정리한 게시글입니다.
DEVOCEAN에 연재 중인 KIDO님의 글을 참고하여 실습한 내용을 기록했습니다.)

 

https://devocean.sk.com/blog/techBoardDetail.do?ID=167054

 

[SpringBatch 연재 10] 스프링배치 플로우 컨트롤 하기

 

devocean.sk.com

 

2. 예제 소스

https://github.com/schooldevops/spring-batch-tutorials/tree/10.01.FlowControl/10.01.FlowControlample

 

spring-batch-tutorials/10.01.FlowControlample at 10.01.FlowControl · schooldevops/spring-batch-tutorials

Contribute to schooldevops/spring-batch-tutorials development by creating an account on GitHub.

github.com

 


Spring Batch Flow Controller

  • 배치 수행 Flow Controll 은 여러 Step 을 정의하고, 조건에 따라 순서대로 실행, 특정 Step 은 건너 뛸 수 있도록 하는 기능.
  • FlowBuilder API 사용하여 설정

Flow Controll 방법

  • next : 현재 Step이 성공적 종료되면 다음 Step 이동 
  • from : 특정 Step 에서 현재 Step 으로 이동
  • on : 특정 ExitStatus에 따라 다음 Step을 결정
  • to : 특정 Step 으로 이동
  • stop : 현재 Flow를 종료
  • end : FlowBuilder를 종료

Flow 컨트롤 샘플 코드

next 

  • Start 스탭 수행 뒤, next 스탭으로 이동
  • next 는 계속해서 추가 가능 (start --> next --> next ... 순으로 진행)

NextStepTaskJobConfiguration.java

package com.ksko.spring_batch.batch_sample.jobs;

import lombok.extern.slf4j.Slf4j;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;

@Slf4j
@Configuration
public class NextStepTaskJobConfiguration {

    public static final String NEXT_STEP_TASK = "NEXT_STEP_TASK";

    @Autowired
    PlatformTransactionManager transactionManager;

    @Bean(name = "step01")
    public Step step01(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
        log.info("------------------ Init myStep -----------------");

        return new StepBuilder("step01", jobRepository)
                .tasklet(new Tasklet() {
                    @Override
                    public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
                        log.info("Execute Step 01 Tasklet ...");
                        return RepeatStatus.FINISHED;
                    }
                }, transactionManager)
                .build();
    }

    @Bean(name = "step02")
    public Step step02(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
        log.info("------------------ Init myStep -----------------");

        return new StepBuilder("step02", jobRepository)
                .tasklet(new Tasklet() {
                    @Override
                    public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
                        log.info("Execute Step 02 Tasklet ...");
                        return RepeatStatus.FINISHED;
                    }
                }, transactionManager)
                .build();
    }

    @Bean
    public Job nextStepJob(Step step01, Step step02, JobRepository jobRepository) {
        log.info("------------------ Init myJob -----------------");
        return new JobBuilder(NEXT_STEP_TASK, jobRepository)
                .incrementer(new RunIdIncrementer())
                .start(step01)
                .next(step02)
                .build();
    }

}

 

실행결과

2024-12-16T21:40:30.166+09:00  INFO 3500 --- [           main] c.k.s.b.j.m.MybatisItemWriterJobConfig   : ------------------ Init flatFileStep -----------------
2024-12-16T21:40:30.191+09:00  INFO 3500 --- [           main] c.k.s.b.j.m.MybatisItemWriterJobConfig   : ------------------ Init flatFileJob -----------------
2024-12-16T21:40:30.197+09:00  INFO 3500 --- [           main] c.k.s.b.j.NextStepTaskJobConfiguration   : ------------------ Init myStep -----------------
2024-12-16T21:40:30.200+09:00  INFO 3500 --- [           main] c.k.s.b.j.NextStepTaskJobConfiguration   : ------------------ Init myStep -----------------
2024-12-16T21:40:30.202+09:00  INFO 3500 --- [           main] c.k.s.b.j.NextStepTaskJobConfiguration   : ------------------ Init myJob -----------------
2024-12-16T21:40:30.344+09:00  INFO 3500 --- [           main] c.k.s.b.BatchSampleApplication           : Started BatchSampleApplication in 2.86 seconds (process running for 3.408)
2024-12-16T21:40:30.347+09:00  INFO 3500 --- [           main] o.s.b.a.b.JobLauncherApplicationRunner   : Running default command line with: []
2024-12-16T21:40:30.716+09:00  INFO 3500 --- [           main] o.s.b.c.l.support.SimpleJobLauncher      : Job: [SimpleJob: [name=NEXT_STEP_TASK]] launched with the following parameters: [{'run.id':'{value=2, type=class java.lang.Long, identifying=true}'}]
2024-12-16T21:40:30.887+09:00  INFO 3500 --- [           main] o.s.batch.core.job.SimpleStepHandler     : Executing step: [step01]
2024-12-16T21:40:30.955+09:00  INFO 3500 --- [           main] c.k.s.b.j.NextStepTaskJobConfiguration   : Execute Step 01 Tasklet ...
2024-12-16T21:40:31.064+09:00  INFO 3500 --- [           main] o.s.batch.core.step.AbstractStep         : Step: [step01] executed in 175ms
2024-12-16T21:40:31.250+09:00  INFO 3500 --- [           main] o.s.batch.core.job.SimpleStepHandler     : Executing step: [step02]
2024-12-16T21:40:31.319+09:00  INFO 3500 --- [           main] c.k.s.b.j.NextStepTaskJobConfiguration   : Execute Step 02 Tasklet ...
2024-12-16T21:40:31.376+09:00  INFO 3500 --- [           main] o.s.batch.core.step.AbstractStep         : Step: [step02] executed in 124ms
2024-12-16T21:40:31.466+09:00  INFO 3500 --- [           main] o.s.b.c.l.support.SimpleJobLauncher      : Job: [SimpleJob: [name=NEXT_STEP_TASK]] completed with the following parameters: [{'run.id':'{value=2, type=class java.lang.Long, identifying=true}'}] and the following status: [COMPLETED] in 702ms
2024-12-16T21:40:31.471+09:00  INFO 3500 --- [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2024-12-16T21:40:31.473+09:00  INFO 3500 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
2024-12-16T21:40:33.284+09:00  INFO 3500 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.

 

step01 -> step02 순차 진행된 것을 확인 할 수 있다.


on

  • 특정 스탭의 종료 조건에 따라 어떤 Step 으로 이동할지 결정 가능
  • 아래 예제는 Step01 먼저 수행 --> 해당 결과에 따라 다음 Step 이동 하는 플로우
    • on("FAILED") 인 경우, step03 수행
    • from(step01).on("COMPLETED") 인 경우 step03 의 결과 완료 라면, step02 수행
  • on 과 from 통해 Step 의 종료 조건에 따라 원하는 플로우 처리 가능

OnStepTaskJobConfiguration.java

package com.ksko.spring_batch.batch_sample.jobs;

import lombok.extern.slf4j.Slf4j;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;

import java.util.Random;

@Slf4j
@Configuration
public class OnStepTaskJobConfiguration {

    public static final String ON_STEP_TASK = "ON_STEP_TASK";

    @Autowired
    PlatformTransactionManager transactionManager;

    @Bean(name = "stepOn01")
    public Step stepOn01(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
        log.info("------------------ Init myStep -----------------");

        return new StepBuilder("stepOn01", jobRepository)
                .tasklet(new Tasklet() {
                    @Override
                    public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
                        log.info("Execute Step 01 Tasklet ...");

                        Random random = new Random();
                        int randomValue = random.nextInt(1000);

                        if (randomValue % 2 == 0) {
                            return RepeatStatus.FINISHED;
                        } else {
                            throw new RuntimeException("Error This value is Odd: " + randomValue);
                        }
                    }
                }, transactionManager)
                .build();
    }

    @Bean(name = "stepOn02")
    public Step stepOn02(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
        log.info("------------------ Init myStep -----------------");

        return new StepBuilder("stepOn02", jobRepository)
                .tasklet(new Tasklet() {
                    @Override
                    public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
                        log.info("Execute Step 02 Tasklet ...");
                        return RepeatStatus.FINISHED;
                    }
                }, transactionManager)
                .build();
    }

    @Bean(name = "stepOn03")
    public Step stepOn03(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
        log.info("------------------ Init myStep -----------------");

        return new StepBuilder("stepOn03", jobRepository)
                .tasklet(new Tasklet() {
                    @Override
                    public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
                        log.info("Execute Step 03 Tasklet ...");
                        return RepeatStatus.FINISHED;
                    }
                }, transactionManager)
                .build();
    }

    @Bean
    public Job onStepJob(Step stepOn01, Step stepOn02, Step stepOn03, JobRepository jobRepository) {
        log.info("------------------ Init myJob -----------------");
        return new JobBuilder(ON_STEP_TASK, jobRepository)
                .incrementer(new RunIdIncrementer())
                .start(stepOn01)
                .on("FAILED").to(stepOn03)
                .from(stepOn01).on("COMPLETED").to(stepOn02)
                .end()
                .build();
    }

}

 

실행 결과

짝수 나오는 경우

2024-12-16T22:15:57.818+09:00  INFO 40216 --- [           main] c.k.s.b.j.m.MybatisItemWriterJobConfig   : ------------------ Init flatFileStep -----------------
2024-12-16T22:15:57.843+09:00  INFO 40216 --- [           main] c.k.s.b.j.m.MybatisItemWriterJobConfig   : ------------------ Init flatFileJob -----------------
2024-12-16T22:15:57.849+09:00  INFO 40216 --- [           main] c.k.s.b.j.NextStepTaskJobConfiguration   : ------------------ Init myStep -----------------
2024-12-16T22:15:57.851+09:00  INFO 40216 --- [           main] c.k.s.b.j.NextStepTaskJobConfiguration   : ------------------ Init myStep -----------------
2024-12-16T22:15:57.852+09:00  INFO 40216 --- [           main] c.k.s.b.j.NextStepTaskJobConfiguration   : ------------------ Init myJob -----------------
2024-12-16T22:15:57.853+09:00  INFO 40216 --- [           main] c.k.s.b.jobs.OnStepTaskJobConfiguration  : ------------------ Init myStep -----------------
2024-12-16T22:15:57.854+09:00  INFO 40216 --- [           main] c.k.s.b.jobs.OnStepTaskJobConfiguration  : ------------------ Init myStep -----------------
2024-12-16T22:15:57.854+09:00  INFO 40216 --- [           main] c.k.s.b.jobs.OnStepTaskJobConfiguration  : ------------------ Init myStep -----------------
2024-12-16T22:15:57.856+09:00  INFO 40216 --- [           main] c.k.s.b.jobs.OnStepTaskJobConfiguration  : ------------------ Init myJob -----------------
2024-12-16T22:15:58.002+09:00  INFO 40216 --- [           main] c.k.s.b.BatchSampleApplication           : Started BatchSampleApplication in 2.596 seconds (process running for 3.114)
2024-12-16T22:15:58.005+09:00  INFO 40216 --- [           main] o.s.b.a.b.JobLauncherApplicationRunner   : Running default command line with: []
2024-12-16T22:15:58.329+09:00  INFO 40216 --- [           main] o.s.b.c.l.support.SimpleJobLauncher      : Job: [FlowJob: [name=ON_STEP_TASK]] launched with the following parameters: [{'run.id':'{value=2, type=class java.lang.Long, identifying=true}'}]
2024-12-16T22:15:58.505+09:00  INFO 40216 --- [           main] o.s.batch.core.job.SimpleStepHandler     : Executing step: [stepOn01]
2024-12-16T22:15:58.570+09:00  INFO 40216 --- [           main] c.k.s.b.jobs.OnStepTaskJobConfiguration  : Execute Step 01 Tasklet ...
2024-12-16T22:15:58.623+09:00  INFO 40216 --- [           main] o.s.batch.core.step.AbstractStep         : Step: [stepOn01] executed in 117ms
2024-12-16T22:15:58.816+09:00  INFO 40216 --- [           main] o.s.batch.core.job.SimpleStepHandler     : Executing step: [stepOn02]
2024-12-16T22:15:58.868+09:00  INFO 40216 --- [           main] c.k.s.b.jobs.OnStepTaskJobConfiguration  : Execute Step 02 Tasklet ...
2024-12-16T22:15:58.919+09:00  INFO 40216 --- [           main] o.s.batch.core.step.AbstractStep         : Step: [stepOn02] executed in 103ms
2024-12-16T22:15:59.023+09:00  INFO 40216 --- [           main] o.s.b.c.l.support.SimpleJobLauncher      : Job: [FlowJob: [name=ON_STEP_TASK]] completed with the following parameters: [{'run.id':'{value=2, type=class java.lang.Long, identifying=true}'}] and the following status: [COMPLETED] in 637ms
2024-12-16T22:15:59.031+09:00  INFO 40216 --- [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2024-12-16T22:15:59.034+09:00  INFO 40216 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
2024-12-16T22:16:00.942+09:00  INFO 40216 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.

 

홀수 나오는 경우

2024-12-16T22:25:35.497+09:00  INFO 41688 --- [           main] c.k.s.b.j.m.MybatisItemWriterJobConfig   : ------------------ Init flatFileStep -----------------
2024-12-16T22:25:35.520+09:00  INFO 41688 --- [           main] c.k.s.b.j.m.MybatisItemWriterJobConfig   : ------------------ Init flatFileJob -----------------
2024-12-16T22:25:35.525+09:00  INFO 41688 --- [           main] c.k.s.b.j.NextStepTaskJobConfiguration   : ------------------ Init myStep -----------------
2024-12-16T22:25:35.526+09:00  INFO 41688 --- [           main] c.k.s.b.j.NextStepTaskJobConfiguration   : ------------------ Init myStep -----------------
2024-12-16T22:25:35.527+09:00  INFO 41688 --- [           main] c.k.s.b.j.NextStepTaskJobConfiguration   : ------------------ Init myJob -----------------
2024-12-16T22:25:35.528+09:00  INFO 41688 --- [           main] c.k.s.b.jobs.OnStepTaskJobConfiguration  : ------------------ Init myStep -----------------
2024-12-16T22:25:35.529+09:00  INFO 41688 --- [           main] c.k.s.b.jobs.OnStepTaskJobConfiguration  : ------------------ Init myStep -----------------
2024-12-16T22:25:35.529+09:00  INFO 41688 --- [           main] c.k.s.b.jobs.OnStepTaskJobConfiguration  : ------------------ Init myStep -----------------
2024-12-16T22:25:35.530+09:00  INFO 41688 --- [           main] c.k.s.b.jobs.OnStepTaskJobConfiguration  : ------------------ Init myJob -----------------
2024-12-16T22:25:35.672+09:00  INFO 41688 --- [           main] c.k.s.b.BatchSampleApplication           : Started BatchSampleApplication in 2.587 seconds (process running for 3.05)
2024-12-16T22:25:35.675+09:00  INFO 41688 --- [           main] o.s.b.a.b.JobLauncherApplicationRunner   : Running default command line with: []
2024-12-16T22:25:35.943+09:00  INFO 41688 --- [           main] o.s.b.c.l.support.SimpleJobLauncher      : Job: [FlowJob: [name=ON_STEP_TASK]] launched with the following parameters: [{'run.id':'{value=6, type=class java.lang.Long, identifying=true}'}]
2024-12-16T22:25:36.127+09:00  INFO 41688 --- [           main] o.s.batch.core.job.SimpleStepHandler     : Executing step: [stepOn01]
2024-12-16T22:25:36.188+09:00  INFO 41688 --- [           main] c.k.s.b.jobs.OnStepTaskJobConfiguration  : Execute Step 01 Tasklet ...
2024-12-16T22:25:36.189+09:00  INFO 41688 --- [           main] c.k.s.b.jobs.OnStepTaskJobConfiguration  : Random value is 845
2024-12-16T22:25:36.189+09:00  INFO 41688 --- [           main] c.k.s.b.jobs.OnStepTaskJobConfiguration  : Random value is odd
2024-12-16T22:25:36.199+09:00 ERROR 41688 --- [           main] o.s.batch.core.step.AbstractStep         : Encountered an error executing step stepOn01 in job ON_STEP_TASK

java.lang.RuntimeException: Error This value is Odd: 845
	at com.ksko.spring_batch.batch_sample.jobs.OnStepTaskJobConfiguration$1.execute(OnStepTaskJobConfiguration.java:49) ~[main/:na]
	at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:388) ~[spring-batch-core-5.1.2.jar:5.1.2]
	at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:312) ~[spring-batch-core-5.1.2.jar:5.1.2]
	at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140) ~[spring-tx-6.1.12.jar:6.1.12]
	at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:255) ~[spring-batch-core-5.1.2.jar:5.1.2]
	at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:82) ~[spring-batch-core-5.1.2.jar:5.1.2]
	at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:369) ~[spring-batch-infrastructure-5.1.2.jar:5.1.2]
	at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:206) ~[spring-batch-infrastructure-5.1.2.jar:5.1.2]
	at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:140) ~[spring-batch-infrastructure-5.1.2.jar:5.1.2]
	at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:240) ~[spring-batch-core-5.1.2.jar:5.1.2]
	at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:229) ~[spring-batch-core-5.1.2.jar:5.1.2]
	at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:153) ~[spring-batch-core-5.1.2.jar:5.1.2]
	at org.springframework.batch.core.job.flow.JobFlowExecutor.executeStep(JobFlowExecutor.java:68) ~[spring-batch-core-5.1.2.jar:5.1.2]
	at org.springframework.batch.core.job.flow.support.state.StepState.handle(StepState.java:68) ~[spring-batch-core-5.1.2.jar:5.1.2]
	at org.springframework.batch.core.job.flow.support.SimpleFlow.resume(SimpleFlow.java:165) ~[spring-batch-core-5.1.2.jar:5.1.2]
	at org.springframework.batch.core.job.flow.support.SimpleFlow.start(SimpleFlow.java:140) ~[spring-batch-core-5.1.2.jar:5.1.2]
	at org.springframework.batch.core.job.flow.FlowJob.doExecute(FlowJob.java:132) ~[spring-batch-core-5.1.2.jar:5.1.2]
	at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:317) ~[spring-batch-core-5.1.2.jar:5.1.2]
	at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:157) ~[spring-batch-core-5.1.2.jar:5.1.2]
	at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50) ~[spring-core-6.1.12.jar:6.1.12]
	at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:148) ~[spring-batch-core-5.1.2.jar:5.1.2]
	at org.springframework.batch.core.launch.support.TaskExecutorJobLauncher.run(TaskExecutorJobLauncher.java:59) ~[spring-batch-core-5.1.2.jar:5.1.2]
	at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.execute(JobLauncherApplicationRunner.java:210) ~[spring-boot-autoconfigure-3.3.3.jar:3.3.3]
	at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.executeLocalJobs(JobLauncherApplicationRunner.java:194) ~[spring-boot-autoconfigure-3.3.3.jar:3.3.3]
	at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.launchJobFromProperties(JobLauncherApplicationRunner.java:174) ~[spring-boot-autoconfigure-3.3.3.jar:3.3.3]
	at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:169) ~[spring-boot-autoconfigure-3.3.3.jar:3.3.3]
	at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:164) ~[spring-boot-autoconfigure-3.3.3.jar:3.3.3]
	at org.springframework.boot.SpringApplication.lambda$callRunner$4(SpringApplication.java:786) ~[spring-boot-3.3.3.jar:3.3.3]
	at org.springframework.util.function.ThrowingConsumer$1.acceptWithException(ThrowingConsumer.java:83) ~[spring-core-6.1.12.jar:6.1.12]
	at org.springframework.util.function.ThrowingConsumer.accept(ThrowingConsumer.java:60) ~[spring-core-6.1.12.jar:6.1.12]
	at org.springframework.util.function.ThrowingConsumer$1.accept(ThrowingConsumer.java:88) ~[spring-core-6.1.12.jar:6.1.12]
	at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:798) ~[spring-boot-3.3.3.jar:3.3.3]
	at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:786) ~[spring-boot-3.3.3.jar:3.3.3]
	at org.springframework.boot.SpringApplication.lambda$callRunners$3(SpringApplication.java:774) ~[spring-boot-3.3.3.jar:3.3.3]
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184) ~[na:na]
	at java.base/java.util.stream.SortedOps$SizedRefSortingSink.end(SortedOps.java:357) ~[na:na]
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:510) ~[na:na]
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) ~[na:na]
	at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151) ~[na:na]
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174) ~[na:na]
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:na]
	at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) ~[na:na]
	at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:774) ~[spring-boot-3.3.3.jar:3.3.3]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:342) ~[spring-boot-3.3.3.jar:3.3.3]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1363) ~[spring-boot-3.3.3.jar:3.3.3]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1352) ~[spring-boot-3.3.3.jar:3.3.3]
	at com.ksko.spring_batch.batch_sample.BatchSampleApplication.main(BatchSampleApplication.java:12) ~[main/:na]

2024-12-16T22:25:36.231+09:00  INFO 41688 --- [           main] o.s.batch.core.step.AbstractStep         : Step: [stepOn01] executed in 102ms
2024-12-16T22:25:36.443+09:00  INFO 41688 --- [           main] o.s.batch.core.job.SimpleStepHandler     : Executing step: [stepOn03]
2024-12-16T22:25:36.500+09:00  INFO 41688 --- [           main] c.k.s.b.jobs.OnStepTaskJobConfiguration  : Execute Step 03 Tasklet ...
2024-12-16T22:25:36.545+09:00  INFO 41688 --- [           main] o.s.batch.core.step.AbstractStep         : Step: [stepOn03] executed in 102ms
2024-12-16T22:25:36.636+09:00  INFO 41688 --- [           main] o.s.b.c.l.support.SimpleJobLauncher      : Job: [FlowJob: [name=ON_STEP_TASK]] completed with the following parameters: [{'run.id':'{value=6, type=class java.lang.Long, identifying=true}'}] and the following status: [COMPLETED] in 646ms
2024-12-16T22:25:36.642+09:00  INFO 41688 --- [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2024-12-16T22:25:36.644+09:00  INFO 41688 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
2024-12-16T22:25:38.713+09:00  INFO 41688 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.

 

홀수나 나오면 exception  뜨는것 확인 할 수 있다.


stop

  • 특정 step의 작업 결과의 상태를 보고 정지할지 결정
  • step1의 결과가 실패인 경우 stop 을 통해 배치작업을 정지한다. (위 2번째 예제는 실패해도 배치는 실행이 끝까지 됨)

 

StopStepTaskJobConfiguration.java

package com.ksko.spring_batch.batch_sample.jobs;

import lombok.extern.slf4j.Slf4j;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;

import java.util.Random;

@Slf4j
@Configuration
public class StopStepTaskJobConfiguration {

    public static final String STOP_STEP_TASK = "STOP_STEP_TASK";

    @Autowired
    PlatformTransactionManager transactionManager;

    @Bean(name = "stepStop01")
    public Step stepStop01(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
        log.info("------------------ Init myStep -----------------");

        return new StepBuilder("stepStop01", jobRepository)
                .tasklet(new Tasklet() {
                    @Override
                    public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
                        log.info("Execute Step 01 Tasklet ...");

                        Random random = new Random();
                        int randomValue = random.nextInt(1000);

                        if (randomValue % 2 == 0) {
                            return RepeatStatus.FINISHED;
                        } else {
                            throw new RuntimeException("Error This value is Odd: " + randomValue);
                        }
                    }
                }, transactionManager)
                .build();
    }

    @Bean(name = "stepStop02")
    public Step stepStop02(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
        log.info("------------------ Init myStep -----------------");

        return new StepBuilder("stepStop02", jobRepository)
                .tasklet(new Tasklet() {
                    @Override
                    public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
                        log.info("Execute Step 02 Tasklet ...");
                        return RepeatStatus.FINISHED;
                    }
                }, transactionManager)
                .build();
    }

    @Bean
    public Job stopStepJob(Step stepOn01, Step stepOn02, Step stepOn03, JobRepository jobRepository) {
        log.info("------------------ Init myJob -----------------");
        return new JobBuilder(STOP_STEP_TASK, jobRepository)
                .incrementer(new RunIdIncrementer())
                .start(stepOn01)
                .on("FAILED").stop()
                .from(stepOn01).on("COMPLETED").to(stepOn02)
                .end()
                .build();
    }

}

 

짝수일 경우

2024-12-16T22:45:33.472+09:00  INFO 29036 --- [           main] c.k.s.b.jobs.OnStepTaskJobConfiguration  : ------------------ Init myStep -----------------
2024-12-16T22:45:33.490+09:00  INFO 29036 --- [           main] c.k.s.b.jobs.OnStepTaskJobConfiguration  : ------------------ Init myStep -----------------
2024-12-16T22:45:33.491+09:00  INFO 29036 --- [           main] c.k.s.b.jobs.OnStepTaskJobConfiguration  : ------------------ Init myStep -----------------
2024-12-16T22:45:33.493+09:00  INFO 29036 --- [           main] c.k.s.b.jobs.OnStepTaskJobConfiguration  : ------------------ Init myJob -----------------
2024-12-16T22:45:33.504+09:00  INFO 29036 --- [           main] c.k.s.b.j.StopStepTaskJobConfiguration   : ------------------ Init myStep -----------------
2024-12-16T22:45:33.505+09:00  INFO 29036 --- [           main] c.k.s.b.j.StopStepTaskJobConfiguration   : ------------------ Init myStep -----------------
2024-12-16T22:45:33.506+09:00  INFO 29036 --- [           main] c.k.s.b.j.StopStepTaskJobConfiguration   : ------------------ Init myJob -----------------
2024-12-16T22:45:33.643+09:00  INFO 29036 --- [           main] c.k.s.b.BatchSampleApplication           : Started BatchSampleApplication in 2.546 seconds (process running for 3.03)
2024-12-16T22:45:33.646+09:00  INFO 29036 --- [           main] o.s.b.a.b.JobLauncherApplicationRunner   : Running default command line with: []
2024-12-16T22:45:34.048+09:00  INFO 29036 --- [           main] o.s.b.c.l.support.SimpleJobLauncher      : Job: [FlowJob: [name=STOP_STEP_TASK]] launched with the following parameters: [{'run.id':'{value=8, type=class java.lang.Long, identifying=true}'}]
2024-12-16T22:45:34.254+09:00  INFO 29036 --- [           main] o.s.batch.core.job.SimpleStepHandler     : Executing step: [stepOn01]
2024-12-16T22:45:34.323+09:00  INFO 29036 --- [           main] c.k.s.b.jobs.OnStepTaskJobConfiguration  : Execute Step 01 Tasklet ...
2024-12-16T22:45:34.323+09:00  INFO 29036 --- [           main] c.k.s.b.jobs.OnStepTaskJobConfiguration  : Random value is 650
2024-12-16T22:45:34.323+09:00  INFO 29036 --- [           main] c.k.s.b.jobs.OnStepTaskJobConfiguration  : Random value is even
2024-12-16T22:45:34.392+09:00  INFO 29036 --- [           main] o.s.batch.core.step.AbstractStep         : Step: [stepOn01] executed in 136ms
2024-12-16T22:45:34.599+09:00  INFO 29036 --- [           main] o.s.batch.core.job.SimpleStepHandler     : Executing step: [stepOn02]
2024-12-16T22:45:34.690+09:00  INFO 29036 --- [           main] c.k.s.b.jobs.OnStepTaskJobConfiguration  : Execute Step 02 Tasklet ...
2024-12-16T22:45:34.741+09:00  INFO 29036 --- [           main] o.s.batch.core.step.AbstractStep         : Step: [stepOn02] executed in 142ms
2024-12-16T22:45:34.858+09:00  INFO 29036 --- [           main] o.s.b.c.l.support.SimpleJobLauncher      : Job: [FlowJob: [name=STOP_STEP_TASK]] completed with the following parameters: [{'run.id':'{value=8, type=class java.lang.Long, identifying=true}'}] and the following status: [COMPLETED] in 757ms
2024-12-16T22:45:34.862+09:00  INFO 29036 --- [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2024-12-16T22:45:34.864+09:00  INFO 29036 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
2024-12-16T22:45:36.613+09:00  INFO 29036 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.

 

 

정상이군..

 

홀수이면 stepon1 에서 2로 못들어가고 바로 종료된것을 확인할 수 있다

2024-12-16T22:46:53.506+09:00  INFO 26336 --- [           main] c.k.s.b.jobs.OnStepTaskJobConfiguration  : ------------------ Init myStep -----------------
2024-12-16T22:46:53.524+09:00  INFO 26336 --- [           main] c.k.s.b.jobs.OnStepTaskJobConfiguration  : ------------------ Init myStep -----------------
2024-12-16T22:46:53.525+09:00  INFO 26336 --- [           main] c.k.s.b.jobs.OnStepTaskJobConfiguration  : ------------------ Init myStep -----------------
2024-12-16T22:46:53.528+09:00  INFO 26336 --- [           main] c.k.s.b.jobs.OnStepTaskJobConfiguration  : ------------------ Init myJob -----------------
2024-12-16T22:46:53.538+09:00  INFO 26336 --- [           main] c.k.s.b.j.StopStepTaskJobConfiguration   : ------------------ Init myStep -----------------
2024-12-16T22:46:53.539+09:00  INFO 26336 --- [           main] c.k.s.b.j.StopStepTaskJobConfiguration   : ------------------ Init myStep -----------------
2024-12-16T22:46:53.541+09:00  INFO 26336 --- [           main] c.k.s.b.j.StopStepTaskJobConfiguration   : ------------------ Init myJob -----------------
2024-12-16T22:46:53.669+09:00  INFO 26336 --- [           main] c.k.s.b.BatchSampleApplication           : Started BatchSampleApplication in 2.444 seconds (process running for 2.93)
2024-12-16T22:46:53.671+09:00  INFO 26336 --- [           main] o.s.b.a.b.JobLauncherApplicationRunner   : Running default command line with: []
2024-12-16T22:46:53.990+09:00  INFO 26336 --- [           main] o.s.b.c.l.support.SimpleJobLauncher      : Job: [FlowJob: [name=STOP_STEP_TASK]] launched with the following parameters: [{'run.id':'{value=10, type=class java.lang.Long, identifying=true}'}]
2024-12-16T22:46:54.229+09:00  INFO 26336 --- [           main] o.s.batch.core.job.SimpleStepHandler     : Executing step: [stepOn01]
2024-12-16T22:46:54.301+09:00  INFO 26336 --- [           main] c.k.s.b.jobs.OnStepTaskJobConfiguration  : Execute Step 01 Tasklet ...
2024-12-16T22:46:54.301+09:00  INFO 26336 --- [           main] c.k.s.b.jobs.OnStepTaskJobConfiguration  : Random value is 727
2024-12-16T22:46:54.301+09:00  INFO 26336 --- [           main] c.k.s.b.jobs.OnStepTaskJobConfiguration  : Random value is odd
2024-12-16T22:46:54.312+09:00 ERROR 26336 --- [           main] o.s.batch.core.step.AbstractStep         : Encountered an error executing step stepOn01 in job STOP_STEP_TASK

java.lang.RuntimeException: Error This value is Odd: 727
	at com.ksko.spring_batch.batch_sample.jobs.OnStepTaskJobConfiguration$1.execute(OnStepTaskJobConfiguration.java:49) ~[main/:na]
	at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:388) ~[spring-batch-core-5.1.2.jar:5.1.2]
	at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:312) ~[spring-batch-core-5.1.2.jar:5.1.2]
	at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140) ~[spring-tx-6.1.12.jar:6.1.12]
	at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:255) ~[spring-batch-core-5.1.2.jar:5.1.2]
	at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:82) ~[spring-batch-core-5.1.2.jar:5.1.2]
	at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:369) ~[spring-batch-infrastructure-5.1.2.jar:5.1.2]
	at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:206) ~[spring-batch-infrastructure-5.1.2.jar:5.1.2]
	at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:140) ~[spring-batch-infrastructure-5.1.2.jar:5.1.2]
	at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:240) ~[spring-batch-core-5.1.2.jar:5.1.2]
	at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:229) ~[spring-batch-core-5.1.2.jar:5.1.2]
	at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:153) ~[spring-batch-core-5.1.2.jar:5.1.2]
	at org.springframework.batch.core.job.flow.JobFlowExecutor.executeStep(JobFlowExecutor.java:68) ~[spring-batch-core-5.1.2.jar:5.1.2]
	at org.springframework.batch.core.job.flow.support.state.StepState.handle(StepState.java:68) ~[spring-batch-core-5.1.2.jar:5.1.2]
	at org.springframework.batch.core.job.flow.support.SimpleFlow.resume(SimpleFlow.java:165) ~[spring-batch-core-5.1.2.jar:5.1.2]
	at org.springframework.batch.core.job.flow.support.SimpleFlow.start(SimpleFlow.java:140) ~[spring-batch-core-5.1.2.jar:5.1.2]
	at org.springframework.batch.core.job.flow.FlowJob.doExecute(FlowJob.java:132) ~[spring-batch-core-5.1.2.jar:5.1.2]
	at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:317) ~[spring-batch-core-5.1.2.jar:5.1.2]
	at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:157) ~[spring-batch-core-5.1.2.jar:5.1.2]
	at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50) ~[spring-core-6.1.12.jar:6.1.12]
	at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:148) ~[spring-batch-core-5.1.2.jar:5.1.2]
	at org.springframework.batch.core.launch.support.TaskExecutorJobLauncher.run(TaskExecutorJobLauncher.java:59) ~[spring-batch-core-5.1.2.jar:5.1.2]
	at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.execute(JobLauncherApplicationRunner.java:210) ~[spring-boot-autoconfigure-3.3.3.jar:3.3.3]
	at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.executeLocalJobs(JobLauncherApplicationRunner.java:194) ~[spring-boot-autoconfigure-3.3.3.jar:3.3.3]
	at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.launchJobFromProperties(JobLauncherApplicationRunner.java:174) ~[spring-boot-autoconfigure-3.3.3.jar:3.3.3]
	at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:169) ~[spring-boot-autoconfigure-3.3.3.jar:3.3.3]
	at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:164) ~[spring-boot-autoconfigure-3.3.3.jar:3.3.3]
	at org.springframework.boot.SpringApplication.lambda$callRunner$4(SpringApplication.java:786) ~[spring-boot-3.3.3.jar:3.3.3]
	at org.springframework.util.function.ThrowingConsumer$1.acceptWithException(ThrowingConsumer.java:83) ~[spring-core-6.1.12.jar:6.1.12]
	at org.springframework.util.function.ThrowingConsumer.accept(ThrowingConsumer.java:60) ~[spring-core-6.1.12.jar:6.1.12]
	at org.springframework.util.function.ThrowingConsumer$1.accept(ThrowingConsumer.java:88) ~[spring-core-6.1.12.jar:6.1.12]
	at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:798) ~[spring-boot-3.3.3.jar:3.3.3]
	at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:786) ~[spring-boot-3.3.3.jar:3.3.3]
	at org.springframework.boot.SpringApplication.lambda$callRunners$3(SpringApplication.java:774) ~[spring-boot-3.3.3.jar:3.3.3]
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184) ~[na:na]
	at java.base/java.util.stream.SortedOps$SizedRefSortingSink.end(SortedOps.java:357) ~[na:na]
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:510) ~[na:na]
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) ~[na:na]
	at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151) ~[na:na]
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174) ~[na:na]
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:na]
	at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) ~[na:na]
	at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:774) ~[spring-boot-3.3.3.jar:3.3.3]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:342) ~[spring-boot-3.3.3.jar:3.3.3]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1363) ~[spring-boot-3.3.3.jar:3.3.3]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1352) ~[spring-boot-3.3.3.jar:3.3.3]
	at com.ksko.spring_batch.batch_sample.BatchSampleApplication.main(BatchSampleApplication.java:12) ~[main/:na]

2024-12-16T22:46:54.342+09:00  INFO 26336 --- [           main] o.s.batch.core.step.AbstractStep         : Step: [stepOn01] executed in 112ms
2024-12-16T22:46:54.441+09:00  INFO 26336 --- [           main] o.s.b.c.l.support.SimpleJobLauncher      : Job: [FlowJob: [name=STOP_STEP_TASK]] completed with the following parameters: [{'run.id':'{value=10, type=class java.lang.Long, identifying=true}'}] and the following status: [STOPPED] in 404ms
2024-12-16T22:46:54.446+09:00  INFO 26336 --- [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2024-12-16T22:46:54.448+09:00  INFO 26336 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
2024-12-16T22:46:56.168+09:00  INFO 26336 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.

 

 

끝났다.. ㅠㅠ 다시 복습 꼭 해야겟다 ㅠㅠ

 

그리고 11주차도 하자..

 

728x90