묻고 답해요
167만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
해결됨죽음의 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
-
미해결스프링 배치
Spring Batch 배포 질문
안녕하세요, 강사님.강사님 강의로 Spring Batch를 공부하고 있는 사람입니다. 다름이 아니라 배포 방법에 있어서 마땅한 방법이 떠오르지 않아 질문을 드리게 되었습니다.AWS Cloud를 활용한 배포에서 하나의 EC2 내부에서 API 서버와 Batch 서버를 같이 돌리게 되면 성능 저하 이슈가 발생하는 것으로 알고 있습니다. 그래서 API 서버용 EC2 1, Batch 서버용 EC2 2 별도의 EC2로 관리하면 성능 저하가 발생하지 않을까라고 생각을 하는데 실제 프로젝트에서도 별도의 프로젝트로 API 서버와 Batch 서버 프로젝트를 따로 개발하나요?
-
미해결스프링 배치
spring batch 버전
현재 spring batch 5.xx 버전인걸로 아는데 4.xx버전과 일부 차이가있다고 들었습니다. 프로젝트 구성 및 의존성 설정 파트에 spring 버전도 2.xx로 되어있어서 현재 저는 spring 3.xx이고 batch도 5.xx 버전을 이용하고있어서 크게 문제가 없는 지 궁금합니다. 버전이 업그레이드되면서 deprecated되거나 더 편한 기능들에 대해서는 따로 제공이 없나요?
-
미해결스프링 배치
retry count 관련 질문
안녕하세요 강사님 좋은 강의 감사드립니다.해당 RetryListener 예제에서 조금 이해되지 않는 부분이 있어 글 남깁니다.CustomItemProcessor에서 아이템이 2일 때 예외가 1번 발생하고 CustomItemWriter에서도 아이템이 2일 때 예외가 1번 발생(예외 총 2번 발생)CustomRetryListener의 onError() 메소드가 총 2번 호출되는데 두 번째 호출될 때 context.getRetryCount()가 2로 찍혀야 되는 것이 아닌가 생각이 들었습니다.제가 해당 예제를 따라서 실습할 때도 그렇고 강의 화면을 봐도 retry count가 모두 1로 찍히고 있습니다.동일한 아이템이어도 process할 때와 write할 때 retry count가 다르게 적용되는 것일까요..?확인해주시고 답변 주시면 많은 도움이 될 것 같습니다.감사합니다.
-
미해결스프링 배치
StepExecutionListener 의 afterStep 에서 return ExitStatus.FAILED 에 의한 동작에 의문이 갑니다.
안녕하세요 선생님, 개인적으로 이 강의를 다 보고,혼자서 이것저것 해보고 있는데, 뭔가 이해가 안되는 현상이 있어서 질문드립니다. 일단 제가 작성한 아주 간단한 Batch 코드를 먼저 공유하겠습니다. (Spring boot 3 + Spring Batch core 5 버전입니다.)```javapackage coding.toast.batch.job.reader.config; import coding.toast.batch.job.reader.listener.EmptyReadFailureListener; import lombok.RequiredArgsConstructor; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.job.builder.JobBuilder; import org.springframework.batch.core.repository.JobRepository; import org.springframework.batch.core.step.builder.StepBuilder; import org.springframework.batch.item.support.ListItemReader; import org.springframework.batch.repeat.RepeatStatus; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.transaction.PlatformTransactionManager; import java.util.List; @Configuration @RequiredArgsConstructor public class CustomItemStreamConfig { private final JobRepository jobRepository; private final PlatformTransactionManager transactionManager; @Bean public Job customItemStreamConfigJob() { return new JobBuilder("customItemStreamConfigJob", jobRepository) .start(customItemStreamConfigStep()) .next(simpleStep2()) .build(); } private Step simpleStep2() { return new StepBuilder("simpleStep", jobRepository) .tasklet((contribution, chunkContext) -> { System.out.println("이게 나오면 안됩니다!"); return RepeatStatus.FINISHED; }, transactionManager).build(); } @Bean public Step customItemStreamConfigStep() { return new StepBuilder("customItemStreamConfigStep", jobRepository) .<Integer, Integer>chunk(5, transactionManager) .reader(new ListItemReader<>(List.of())) // 고의적으로 비워놨습니다! .writer(chunk -> { chunk.getItems().forEach(System.out::println); }) .listener(emptyReadFailureListener()) .build(); } @Bean public EmptyReadFailureListener emptyReadFailureListener() { return new EmptyReadFailureListener(); } } 여기서 EmptyReadFailureListener 타입의 인스턴스를 빈으로 등록하고, 이를 Step 의 listener 로 등록했습니다. 이 리스너의 역할은 ItemReader 로 부터 읽은 것이 아무것도 없을 때 Step 이 FAILED 되도록 하기 위한 것입니다. 자세한 내용은 아래와 같습니다.package coding.toast.batch.job.reader.listener; import org.springframework.batch.core.*; public class EmptyReadFailureListener implements StepExecutionListener { @Override public ExitStatus afterStep(StepExecution stepExecution) { if (stepExecution.getReadCount() > 0) { return stepExecution.getExitStatus(); } else { return ExitStatus.FAILED.addExitDescription("exit Because Of No Item Read"); } } } 위처럼 작성했습니다.저는 위의 Job 을 실행하면...Job 의 BatchStatus 와 ExitStatus 모두 FAILED 가 된다.simpleStep 은 이전 Step 에서 ExitStatus Failed 가 됐으므로 실행되지 않는다. ... 하지만 정확히 정반대의 결과가 나왔습니다 😅😅 batch_job_execution 테이블의 결과: batch_step_execution 테이블의 결과: 보시는 바와 같이 Job 자체는 Completed 로 끝이 났습니다.또한 실행되지 않았으면 했던 두번째 step(=simpleStep) 도 실행이 되버리더라구요... 질문:1. 왜 이렇게 동작하는 걸까요? 혹시 ExitStatus 에 대해서 뭔가 잘못 알고 있는 걸까요?2. 그리고 이를 해결하기 위해서는 EmptyReadFailureListener 를 어떻게 고치면 좋을까요? 아니면 혹시 더 좋은 방법이 있을까요??
-
미해결스프링 배치
jdbc, jpa 커서방식 조회 방식 차이 질문 (강사님께 답변 받고 싶습니다)
안녕하세요커서방식에서 Jdbc는 최초 open 메서드 호출 때 db에 쿼리를 날려 ResultSet 첫번 째 row를 가져온 상태에서 read() 를 반복해서 db resultset 커서를 하나씩 이동 시켜 스트리밍 방식으로 가져오는 걸로 알고 있습니다.jpa도 마찬가지로 최초 open 메서드에 쿼리를 날려 작업 결과를 가져오는데 이 때 ResultStream을 반환하고 read에서 실제 db와 상호작용하지 않고 list의 반복자 패턴으로 하나씩 가져온다고 이해했는데요. read때 db와 상호작용을 하지 않는다고 하면 처음 ResultStream에 결과를 다 가져온다는 소리인데 이렇게 되면 메모리 효율이 떨어지지 않나요?