묻고 답해요
161만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결스프링 배치
질문이 있습니다.
강의 내용이 전반적으로 이론 위주로 구성된 것 같은데요, 혹시 강의 후반부도 비슷한 흐름으로 진행될까요?개인적으로 실무에서 바로 적용 가능한 사용 예제나 흐름이 궁금해서 그런데, 혹시 그런 예제가 포함되어 있는지 궁금합니다.감사합니다!
-
미해결죽음의 Spring Batch: 새벽 3시의 처절한 공포는 이제 끝이다.
FaultTolerant의 retryLimit() 횟수 질문
킬구형 안녕, Fault Tolerant 쪽에서,retryLimit()을 설명해줄 때만약 retryLimit 값이 3일경우, "첫번째 호출시도 1번, 재시도 호출 2번"으로 총 3번이 호출된다고 했잖아.재시도 횟수는 항상 retryLimit - 1 이라 그랬고. 근데 왜 "ItemProcessor의 예외 발생 시 재시도 - 아이템 단위로 재시도 관리"의 마지막 호출 결과 찍어준 부분에서, retryLimit()은 3인데 왜 ItemProcessor는 4번이 호출되는거야?위에 설명한대로라면 3번만 호출되어야 하는거 아냐?
-
미해결죽음의 Spring Batch: 새벽 3시의 처절한 공포는 이제 끝이다.
결과 값의 정렬
멀티 스레딩에서 파일에 write할 때 질문이 있습니다.thread가 chunk 단위로 파일에 입력되는것은 확인했습니다.그런데 결과 값의 정렬은 불가능한가요????예를 들어 db에 1, 2, 3, 4, 5 ... 라는 데이터가 있고 FlatFileItemWriter로 파일에 쓸 경우 1,2,3,4,5 이런식으로 정렬된 값이 저장 가능한지
-
미해결죽음의 Spring Batch: 새벽 3시의 처절한 공포는 이제 끝이다.
JpaPagingItemReader
humanThreatDataReader는 스레드 안전한 JpaPagingItemReader를 사용했다.라는 구문에서 헷갈리는게 있는데 JpaPagingItemReader의 경우는 lock을 걸지 않는데 SynchronizedItemStreamReader 데코레이터를 적용해야하지 않나요???
-
미해결죽음의 Spring Batch: 새벽 3시의 처절한 공포는 이제 끝이다.
상태 질문
상태(State): 작전 수행 지점들상태(State)란 Flow 내에서 현재 실행이 머무르거나 도달할 수 있는 모든 논리적 지점을 의미한다. 자동문의 "문 닫힘/문 열림"에 해당한다.Flow를 구성하는 상태(State)는 크게 두 가지 주요 유형으로 분류할 수 있다.실행 상태 (StepState 등):실행 상태는 Flow 내에서 실제 특정 작업(로직)을 수행하는 지점을 나타낸다. 우리 강의의 예제 코드에서 사용된 analyzeContentStep, publishLectureStep, summarizeFailureStep과 같은 Step이 대표적인 실행 상태(StepState)에 해당한다. 종료 상태 (EndState): 종료 상태는 Flow 실행의 최종 도착점을 나타내는 상태이다. Flow가 이 상태에 도달하면 더 이상 진행되지 않고 실행이 종료된다. Job의 최종 결과는 Flow가 어떤 EndState로 끝났는지에 따라 결정된다. 다이어그램의 [작업 종료]가 바로 이 종료 상태(EndState)를 가리킨다. 종료 상태(EndState): Flow 실행의 최종 도착점이다. 이 상태에 도달하면 실행 흐름이 더 이상 진행되지 않고 Flow가 종료된다. Job의 최종 결과는 어떤 EndState로 끝났는지에 따라 결정되며, 앞선 다이어그램의 [작업 종료]가 바로 이 종료 상태(EndState)에 해당한다. 여기서 종료 상태가 두개인데 다른 내용인가요???
-
미해결죽음의 Spring Batch: 새벽 3시의 처절한 공포는 이제 끝이다.
JpaCursorItemReader 질문
이 기본 구현에서 호출하는 getResultList() 는 전체 데이터를 메모리에 한 번에 로딩하므로 실제 스트리밍이 아니며 따라서 타 JPA 구현체 사용 시 주의가 필요하다.라고 하셨는데 JpaCursorItemReader를 이용하면 모든 데이터를 메모리로 가져오기 때문에 OutOfMemoryError가 날 수 있나요??추가로 실무에서는 쿼리가 복잡할텐데 JPA 보단 JDBC를 사용하는 편인가요???
-
미해결죽음의 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; } }; } }이렇게 되어있습니다.