묻고 답해요
164만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결죽음의 Spring Batch: 새벽 3시의 처절한 공포는 이제 끝이다.
잘못된 csv 파일
csv 파일 중 프로세스 아이디 정보가 잘못되어있습니다.실제 SystemFailure의 processId는 Integer인데 csv 파일은 String입니다.
-
미해결죽음의 Spring Batch: 새벽 3시의 처절한 공포는 이제 끝이다.
배치 애플리케이션 패키지 구조
현재 배치 강의를 20퍼 정도 수강 했는데, 배치 애플리케이션을 만들 때 step, job 등 여러 클래스가 있을 텐데 어떤 패키지 구조로 만드는지 궁금합니다.
-
미해결[스프링 배치 입문] 예제로 배우는 핵심 Spring Batch
spring batch 5.x 버전 설정
@SpringBootApplication class SpringBatchTutorialApplication fun main(args: Array<String>) { runApplication<SpringBatchTutorialApplication>(*args) }@EnableBatchProcessing 은 3.x 부터 사용하지 않습니다. spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/batchex username: root password: root123 batch: job: names: ${job.name=NONE} enabled: true jdbc: initialize-schema: always jpa: show-sql: true logging: level: org.springframework.batch: DEBUG @Configuration class HelloWorldJobConfig( private val jobRepository: JobRepository, private val platformTransactionManager: PlatformTransactionManager, ) { @Bean fun helloWorldJob(): Job = JobBuilder("helloWorldJob", jobRepository) .incrementer(RunIdIncrementer()) .start(helloWorldStep()) .build() @JobScope @Bean fun helloWorldStep() = StepBuilder("helloWorldStep", jobRepository) .tasklet(helloWorldTasklet(), platformTransactionManager) .build() @StepScope @Bean fun helloWorldTasklet(): Tasklet = Tasklet { contribution, context -> println("Hello, World from Kotlin Tasklet!") println("Hello, World from Kotlin Tasklet!") println("Hello, World from Kotlin Tasklet!") RepeatStatus.FINISHED } } program arguments 설정하고 실행하면 잘 될겁니다.
-
미해결죽음의 Spring Batch: 새벽 3시의 처절한 공포는 이제 끝이다.
@StepScope 질문
@Bean public Step systemDestructionStep( SystemInfiltrationTasklet tasklet // Tasklet을 주입받는다 ) { return new StepBuilder("systemDestructionStep", jobRepository) .tasklet(tasklet, transactionManager) .build(); } @Slf4j @Component @StepScope // Tasklet에 StepScope를 달았다 public class SystemInfiltrationTasklet implements Tasklet { private final String targetSystem; public SystemInfiltrationTasklet( @Value("#{jobParameters['targetSystem']}") String targetSystem ) { this.targetSystem = targetSystem; } @Override public RepeatStatus execute(StepContribution contribution, ChunkContext context) { log.info("{} 시스템 침투 시작", targetSystem); return RepeatStatus.FINISHED; } }여기서 @StepScope를 tasklet에 작성하는 이유가 있나요?아래 방식처럼 Step에 @StepScope를 작성하면 안되나요?@Bean @StepScope public Step systemDestructionStep( SystemInfiltrationTasklet tasklet // Tasklet을 주입받는다 ) { return new StepBuilder("systemDestructionStep", jobRepository) .tasklet(tasklet, transactionManager) .build(); }
-
미해결죽음의 Spring Batch: 새벽 3시의 처절한 공포는 이제 끝이다.
예시코드 오타 제보
킬구형 일부러 그런건진 모르겠는데, 우선은 Batch Listener 섹션에서 실행명령에 전부--job.name=~~ 형식으로 되어있어. 잡이름을 인식 못해서 Job Bean이 여러개 명시되어있으면 실행할때 오류나는 것 같아.--spring.batch.job.name= 처럼 안하면 안될 것 같은데, 이건 의도적으로 줄인걸까?
-
해결됨죽음의 Spring Batch: 새벽 3시의 처절한 공포는 이제 끝이다.
[예시 코드 오타 제보]처형부탁한다
한다 제보를 KILL-9, 바란다 응답[제보 정보 수집중...🤖][KILL-9@user]$ cd 커리큘럼/섹션4/3장/작전1해킹 주문 데이터베이스 정찰 작전에서 프락치를 발견했다JdbcPagingItemReader 가 whereClause에 거짓 증거를 제출해서 혼란을 야기했다status = 'READY_FOR_SHIPMENT' 이고 not null 이어햐 하지 않을까 생각한다CANCELLED 가 아닌 것 같다다시 보니 작전에 혼동이 있는 것 같다 확인요망 🔥 유해 게시물 처형 작전 시스템에도 버그가 발견됐다전체코드에서 JpaCursorItemReader 에 queryString 조건이 잘못된 것 같다이후의 예시 코드들은 잘돼있지만전체코드 복사하는 녀석들이 많기 때문에 처리부탁한다[추가 처형 요청...💀][KILL-9@user]$ cd 커리큘럼/섹션3/2장/작전1글 쓰는 김에 한 녀석도 추가 제보하겠다FlatFileItemReader 고정길이 예제도 처형 부탁한다 소제목인 .columns() 예제 이미지가 정확하다하지만 예시코드라고 적혀있는 Range는 틀렸다 이것은 KILL-9 후보생의 혼란만 가중시킬뿐이다
-
미해결죽음의 Spring Batch: 새벽 3시의 처절한 공포는 이제 끝이다.
스케줄러
내가 시간이 없어 한 바퀴쭉 훑고 있는데 스케줄러를 활용한 배치 내용은 원래 없는 거냐?내가 못 찾는 거냐?아님 추가 예정이냐 답변 부탁한다.
-
미해결죽음의 Spring Batch: 새벽 3시의 처절한 공포는 이제 끝이다.
배치 람다 or ec2
웹/배치 리소스 사용 부분에서 배치는 필요 할 때만 실행이된다고 했는데 예전에 공공API를 한번 호출 할 때 오래 걸렸던걸로 기억이 난다. 외부API를 1번 호출 할 때 10개씩 가져오는데 약 1분이 걸린다면 1년치 데이터(약 40만건)을 적재를 했어야했다. AWS를 잘 모르지만 람다에서 함수 호출 1번 할 때 최대 15분이라 한번 배치를 돌려서 40만건을 쌓을려면 람다를 도입하기 힘들다고 판단했다. 필요 할 때만 이용하는 람다가 이점이긴하지만 1년치 데이터를 쌓는 부분에서 고민이된다. 아니면 람다를 반복 호출하는게 맞는지... 공공API 1번 호출 할 때 데이터 10건이라 데이터 약 40만건 쌓을려면 4만번 호출한다.그래서 EC2를 도입했었는데, 1년치만 쌓을 때 EC2를 쓰고 그 이후에는 람다를 도입하는게 맞을지 궁금하다.(반말 죄송합니다ㅠㅠ)
-
미해결스프링 배치
ChunkListener 에서 beforeChunk 의 실행 시점 관련 질문
안녕하세요, 강의를 보면서 궁금한 점이 생겨서요. 강의 상에서는 beforeChunk 가 트랜잭션 밖에서, ItemReader 의 read 메소드 이전에 실행된다고 작성되어 있습니다만, 스프링 공식 문서의 설명에 따르면beforeChunk 는 트랜잭션 안에서 실행된다고 설명되어 있습니다.https://docs.spring.io/spring-batch/docs/current/api/org/springframework/batch/core/ChunkListener.html 추가로, ChunkListener 강의 내용 15:05 에 보면 beforeChunk 가 runInTransaction 내부에서 실행되는 것을 볼 수 있습니다. 어떤 내용이 정확한지 부가 설명 부탁드립니다.
-
미해결[스프링 배치 입문] 예제로 배우는 핵심 Spring Batch
Spring Batch 5버전의 경우 실행법 공유
잡 파라미터 넣는것으로는 실행아 안되고요 runJob 메소드 만들어서 실행해야합니다.코드 공유public class SpringBatchTutorialApplication { @Autowired private JobLauncher jobLauncher; @Autowired private Job helloWorldJob; @Autowired private JobRegistry jobRegistry; public static void main(String args[]) { SpringApplication.run(SpringBatchTutorialApplication.class, args); SpringApplication application = new SpringApplication(SpringBatchTutorialApplication.class); application.run(args).getBean(SpringBatchTutorialApplication.class).runJob(args); //System.out.println(args[0]); } public void runJob(String args[]) { try { String jobName = getJobNameFromArgs(args); System.out.println(jobName); Job job = jobRegistry.getJob(jobName); JobExecution jobExecution = jobLauncher.run(job, new JobParameters()); System.out.println("Job Execution Status: " + jobExecution.getStatus()); } catch (Exception e) { e.printStackTrace(); } } private String getJobNameFromArgs(String args[]) { for (String arg : args) { if (arg.startsWith("JobName=")) { return arg.substring("JobName=".length()); } } return null; } }
-
미해결스프링 배치
여러 JOB 설정하는법
현재 버전에서는 YML에서 names로 job을 여러개 등록하는게 불가능한데최신 버전 기준으로 JOB을 여러개 설정할 수 없을까요?
-
미해결스프링 배치
강의 자료 다른 방법 있을까요?
맥을 사용중인데 DB 스키마 생성 및 이해(1) 파트에서 자료 다운로드가 불가능해서요 다른데서 다운로드 가능한게 있을까요?
-
미해결스프링 배치
JobExecution과 JobExecutionContext와의 관계
Q1) JobExecution과 JobExecutionContext는 job이 실행될때마다 생기는게 맞나요?Q2) 맞다면 강의 예제와 같이 같은 job을 두 번 실행(첫번째 실패, 두번째 성공) 했을때 두번째 JobExecutionContext가 첫번째 JobExeuctionContext에 저장된 내용을 알수있다는게 이해가 되지 않습니다. 하지만 실제로 참고해서 동작하고 있고요. 그렇다면 같은 job이고 같은 jobParameter로 연속해서 실행하면 이전 잡을 복사해서 생성이 되나요? 아니면 다른 방법이 있나요?
-
미해결[스프링 배치 입문] 예제로 배우는 핵심 Spring Batch
질문입니다.
Program Arguments가 없어서 VM options에 -Dspring.batch.job.names=helloWorldJob이와같이 설정하여 실행하였고 test파일의 경우 -Dspring.batch.job.names=helloWorldJob -DfileName=test.csv 이렇게 설정하였는데fileName의 경우 null이 나오는데 현재 저의 코드는 package com.example.SpringBatchTutorial.job.ValidatedParam; import lombok.RequiredArgsConstructor; import org.junit.Test; import org.springframework.batch.core.*; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.JobScope; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepScope; import org.springframework.batch.core.launch.JobLauncher; import org.springframework.batch.core.launch.support.RunIdIncrementer; import org.springframework.batch.core.scope.context.ChunkContext; import org.springframework.batch.core.step.tasklet.Tasklet; import org.springframework.batch.repeat.RepeatStatus; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /* desc : 파일 이름 파라미터 전달 그리고 검증 run : --spring.batch.job.names=helloWorldJob - fileName=test.csv * */ @Configuration @RequiredArgsConstructor public class ValidatorParamJobConfig { @Autowired private JobBuilderFactory jobBuilderFactory; @Autowired private StepBuilderFactory stepBuilderFactory; @Autowired private JobLauncher jobLauncher; @Autowired private Job validatedParamJob; @Test public void testJob() throws Exception { // JobParameters에 fileName을 명시적으로 추가 JobParameters jobParameters = new JobParametersBuilder() .addString("fileName", "test.csv") // fileName 전달 .toJobParameters(); // Job 실행 jobLauncher.run(validatedParamJob, jobParameters); } @Bean public Job ValidatedParamJob(Step ValidatedParamStep){ return jobBuilderFactory.get("ValidatedParamJob") .incrementer(new RunIdIncrementer()) .start(ValidatedParamStep) .build(); } @JobScope @Bean public Step ValidatedParamStep(Tasklet ValidatedParamTasklet){ return stepBuilderFactory.get("ValidatedParamStep") .tasklet(ValidatedParamTasklet) .build(); } @Bean @StepScope public Tasklet ValidatedParamTasklet(@Value("#{jobParameters['fileName']}") String fileName){ return new Tasklet() { @Override public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { System.out.println(fileName); System.out.println("Validated Param Tasklet"); return RepeatStatus.FINISHED; } }; } }이렇게 되어있습니다.
-
미해결스프링 배치
특정 job만 실행
해당 강의를 보고 jenkins를 이용해서 spring batch를 실행하려고합니다. 현재 application.yml은 아래와 같이 enabled: false로 해놓았습니다.spring: batch: job: fail-on-job-failure: true enabled: false jdbc: initialize-schema: never젠킨스의 파이프라인인데 파라미터 주입은 잘되었습니다. 그런데 job은 생성이 되었다고 로그가 찍히고 spring도 실행중인데 명시해놓은 job을 실행을 안하네요...2025-03-08T12:51:30.900+09:00 INFO 5801 --- [ main] l.l.e.job.LostItemSearchJobConfig : 🔵 Job 생성: dailyElasticStoreJob 2025-03-08T12:51:32.179+09:00 INFO 5801 --- [ main] l.l.LostNoMoreBatchApplication : Started LostNoMoreBatchApplication in 13.915 seconds (process running for 15.394) Abjava -Duser.timezone=Asia/Seoul -jar /var/jenkins_home/LOST-NO-MORE.jar \\ --spring.batch.job.names=dailyElasticStoreJob \\ --spring.batch.job.parameters="START_DATE=${params.START_DATE},END_DATE=${params.END_DATE}"application.yml에서 enabled: true로하고 job:name=dailyElasticStoreJob로하니깐 되고 어떤게 문제인지 모르겠습니다. 파이프라인은 문제가 없는데 자꾸 spring이 실행 중이고 job을 구동하지 않네요. 직접 JobLauncher를 이용해야하는 방법 밖에 없는 지 궁금합니다.
-
미해결[스프링 배치 입문] 예제로 배우는 핵심 Spring Batch
소스 다운 받을 수 없는건가요?
소스 다운 받을 수 없는건가요?
-
미해결[스프링 배치 입문] 예제로 배우는 핵심 Spring Batch
학습에 사용하는 문서 자료 같은 건 없나요?
학습에 사용하는 문서 자료 같은 건 없나요?
-
미해결스프링 배치
Batch 성능 질문
- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요! - 먼저 유사한 질문이 있었는지 검색해보세요. - 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요.이 강의를 들으면서 프로젝트에 Batch를 도입하려고합니다.Jenkins에서 파라미터로 Spring Batch에 pageNo이라는 인자에 주입하고 Tasklet 인터페이스를 implements한 커스텀 tasklet에서 공공데이터 포털 api를 호출하여 데이터를 가져오고 이를 db에 적재를 하려고 합니다. Job을 1번 실행하면 Step도 1번 실행하는 방식인데 1번 배치 사이클이 끝나면 pageNo을 1 증가해서 다시 배치를 돌리는 방식입니다. 그래서 아래와 같이 2가지 구현을 생각했습니다. Job은 1번 호출하지만 Step을 반복 실행 VS Job을 반복 호출=======================================전자 방식-장점: 메타 테이블에 JobExecution 등 db에 삽입 및 조회가 많이 일어나지 않는다.-단점: 특정 pageNo이 오류가 날 시 몇번째 pageNo에서 오류가 났는 지 확인을 해야하는데 이를 StepExecutionContext에서 디코딩 후 자바 역직렬화를 해야한다.(DB에서 조회만으로 확인하기 힘듦)=======================================후자 방식-장점: DB에서 조회만으로 pageNo이 몇번째에서 오류가 발생했는 지 쉽게 확인 할 수 있다.-단점: DB에 접근이 많다.=======================================제가 직접 느낀바로는 위와 같습니다. 저도 아직 공부한지 얼마 안되어서 잘 모르기에 Chat GPT에게 물어봤습니다. 아래와 같이 Job을 반복 호출하는건 성능상 좋지 않다고 합니다. GPT의 답변이 정답이 아닐 수 있기에 확인도 받고싶고 만약 Step을 반복적으로 호출하는게 더 낫다면 API용 Spring 서버에서 관리자가 로그인하면 이를 StepExecutionContext에서 가져와서 역직렬화 후 브라우저에 보여주는게 더 나은가싶습니다. 선생님께 자문을 구하고싶습니다.
-
미해결스프링 배치
ItemReaderAdapter 종료
ItemReaderAdapter를 사용할 일이 있어서 사용하던 중 조회해온 데이터가 null 일 경우에 배치가 종료가 되어야는데 종료가 안되고 무한히 반복됩니다.. 무엇이 문제일까요??reader(itemReader) .writer(itemWriter) .faultTolerant() .skip(Throwable.class) //모든 예외조건에 대해서 skip 실행 .skipLimit(Integer.MAX_VALUE) .allowStartIfComplete(false) .build();if (객체!= null) { adapter.setTargetObject(this); adapter.setTargetMethod(""); adapter.setArguments(new Object[]{object}); return adapter; } else { return null; } }
-
미해결스프링 배치
[ 강좌 Git 브랜치 문의 ] 섹션 9 > JdbcCursorItemReader, JpaCursorItemReader
섹션 9 > JdbcCursorItemReader, JpaCursorItemReader 강좌 Git 브랜치 정보 문의드립니다. 계속 찾아봐도 못찾겠습니다. Part6.X.X 를 모두 뒤져도 안나옵니다.아시는분 댓글 부탁드립니다 ^^; 강의에서의 파일 중에 특히 리소스 폴더의 아래 2개 파일을 도저히 못찾겠습니다.data-mysql.sqlschema-mysql.sql