묻고 답해요
169만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결죽음의 Spring Batch: 새벽 3시의 처절한 공포는 이제 끝이다.
[건의][6장][작전1] deprecated 메소드
형 ... @Bean public Step threatAnalysisStep( JpaPagingItemReader<Human> humanThreatDataReader, ItemProcessor<Human, TargetPriorityResult> threatAnalysisProcessor, FlatFileItemWriter<TargetPriorityResult> targetListWriter ) { return new StepBuilder("threatAnalysisStep") .<Human, TargetPriorityResult>chunk(10, transactionManager) .reader(humanThreatDataReader) .processor(threatAnalysisProcessor) .writer(targetListWriter) .taskExecutor(taskExecutor()) // deprecated 되어서 안씀 // .throttleLimit() .build(); } ... 에서 .throttleLimit() 부분이 5 이후로 deprecated 된다고 명시되어 있어. 관심사 분리로 인해서 taskExecutor 정의 부분에서 설정하라고 권장하는 것을 확인했거든. 현재 강의가 사실상 Spring Batch 5.x 까지의 기본 내용과 원리를 살펴봤잖아 ? 그렇다 하더라도 혼란을 줄 수 있기 때문에 해당 부분은 삭제하던지 아니면 추가 내용을 기재해야 할 것으로 보여.
-
미해결죽음의 Spring Batch: 새벽 3시의 처절한 공포는 이제 끝이다.
[예제][3장][작전2] windows 에서 마지막 예제
... @Slf4j @Configuration @RequiredArgsConstructor public class LogProcessingJobConfig { private final JobRepository jobRepository; private final PlatformTransactionManager transactionManager; private final String BASE_PATH = "C:\\Users\\user\\Desktop\\batch\\section3\\flatfileitemwriter"; @Bean public Job logProcessingJob( Step createDirectoryStep, Step logCollectionStep, Step logProcessingStep ) { return new JobBuilder("logProcessingJob", jobRepository) .start(createDirectoryStep) .next(logCollectionStep) .next(logProcessingStep) .build(); } @Bean public Step createDirectoryStep(SystemCommandTasklet mkdirTasklet) { return new StepBuilder("createDirectoryStep", jobRepository) .tasklet(mkdirTasklet, transactionManager) .build(); } @Bean @StepScope public SystemCommandTasklet mkdirTasklet( @Value("#{jobParameters['date']}") String date ) { SystemCommandTasklet tasklet = new SystemCommandTasklet(); tasklet.setWorkingDirectory(BASE_PATH); String collectedLogsPath = "collected_ecommerce_logs\\" + date; String processedLogsPath = "processed_logs\\" + date; try { tasklet.setCommand("cmd.exe", "/c", "mkdir", collectedLogsPath, processedLogsPath); tasklet.setTimeout(3000); } catch (Exception e) { log.error("mkdirTasklet error: ", e); } return tasklet; } @Bean public Step logCollectionStep(SystemCommandTasklet scpTasklet) { return new StepBuilder("logCollectionStep", jobRepository) .tasklet(scpTasklet, transactionManager) .build(); } @Bean @StepScope public SystemCommandTasklet scpTasklet( @Value("#{jobParameters['date']}") String date ) { SystemCommandTasklet tasklet = new SystemCommandTasklet(); tasklet.setWorkingDirectory(BASE_PATH); String processedLogsPath = "collected_ecommerce_logs\\" + date; StringJoiner commandBuilder = new StringJoiner(" & "); for (String host : List.of("localhost")) { // Windows 환경에서 해당 코드를 적용하려면 ssh 관련 설정들을 찾아야 해서 주석 처리 // String command = String.format("scp %s:~/ecommerce_logs/%s.log %s\\%s.log", host, date, processedLogsPath, host); String sourcePath = BASE_PATH + "\\ecommerce_logs\\" + date + ".log"; String command = String.format("copy %s %s\\%s.log", sourcePath, processedLogsPath, host); commandBuilder.add(command); } tasklet.setCommand("cmd.exe", "/c", commandBuilder.toString()); tasklet.setTimeout(10000); return tasklet; } @Bean public Step logProcessingStep( MultiResourceItemReader<LogEntry> multiResourceItemReader, LogEntryProcessor logEntryProcessor, FlatFileItemWriter<ProcessedLogEntry> processedLogEntryJsonWriter ) { return new StepBuilder("logProcessingStep", jobRepository) .<LogEntry, ProcessedLogEntry>chunk(10, transactionManager) .reader(multiResourceItemReader) .processor(logEntryProcessor) .writer(processedLogEntryJsonWriter) .build(); } @Bean @StepScope public MultiResourceItemReader multiResourceItemReader( @Value("#{jobParameters['date']}") String date ) { MultiResourceItemReader<LogEntry> resourceItemReader = new MultiResourceItemReader<>(); resourceItemReader.setName("multiResourceItemReader"); resourceItemReader.setResources(getResources(date)); resourceItemReader.setDelegate(logFileReader()); return resourceItemReader; } private Resource[] getResources(String date) { try { String formattedBasePath = BASE_PATH.replace("\\", "/"); String location = "file:///" + formattedBasePath + "/collected_ecommerce_logs/" + date + "/*.log"; PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); return resolver.getResources(location); } catch (IOException e) { throw new RuntimeException("Failed to resolve log files", e); } } @Bean public FlatFileItemReader<LogEntry> logFileReader() { return new FlatFileItemReaderBuilder<LogEntry>() .name("logFileReader") .delimited() .delimiter(",") .names("dateTime", "level", "message") .targetType(LogEntry.class) .build(); } @Bean public LogEntryProcessor logEntryProcessor() { return new LogEntryProcessor(); } @Bean @StepScope public FlatFileItemWriter<ProcessedLogEntry> processedLogEntryFlatFileItemWriter( @Value("#{jobParameters['date']}") String date ) { String outputPath = Paths.get(BASE_PATH, "processed_logs", date, "processed_logs.jsonl").toString(); ObjectMapper objectMapper = new ObjectMapper(); JavaTimeModule javaTimeModule = new JavaTimeModule(); javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"))); objectMapper.registerModule(javaTimeModule); return new FlatFileItemWriterBuilder<ProcessedLogEntry>() .name("processedLogEntryJsonWriter") .resource(new FileSystemResource(outputPath)) .lineAggregator(item -> { try { return objectMapper.writeValueAsString(item); } catch (JsonProcessingException e) { throw new RuntimeException("Error Converting item to JSON", e); } }) .build(); } @Data public static class LogEntry { private String dateTime; private String level; private String message; } @Data public static class ProcessedLogEntry { private LocalDateTime dateTime; private LogLevel level; private String message; private String errorCode; } public enum LogLevel { INFO, WARN, ERROR, DEBUG, UNKNOWN; public static LogLevel fromString(String level) { if (level == null || level.trim().isEmpty()) { return UNKNOWN; } try { return valueOf(level.toUpperCase()); } catch (IllegalArgumentException e) { return UNKNOWN; } } } public static class LogEntryProcessor implements ItemProcessor<LogEntry, ProcessedLogEntry> { private static final DateTimeFormatter ISO_FORMATTER = DateTimeFormatter.ISO_DATE_TIME; private static final Pattern ERROR_CODE_PATTERN = Pattern.compile("ERROR_CODE\\[(\\w+)]"); @Override public ProcessedLogEntry process(LogEntry item) throws Exception { ProcessedLogEntry processedLogEntry = new ProcessedLogEntry(); processedLogEntry.setDateTime(parseDateTime(item.getDateTime())); processedLogEntry.setLevel(parseLevel(item.getLevel())); processedLogEntry.setMessage(item.getMessage()); processedLogEntry.setErrorCode(extractErrorCode(item.getMessage())); return processedLogEntry; } private LocalDateTime parseDateTime(String dateTime) { return LocalDateTime.parse(dateTime, ISO_FORMATTER); } private LogLevel parseLevel(String level) { return LogLevel.fromString(level); } private String extractErrorCode(String message) { if (message == null) { return null; } Matcher matcher = ERROR_CODE_PATTERN.matcher(message); if (matcher.find()) { return matcher.group(1); } // ERROR 문자열이 포함되어 있지만 패턴이 일치하지 않는 경우 if (message.contains("ERROR")) { return "UNKNOWN_ERROR"; } return null; } } } 윈도우즈에서는 scp 명령어 관련해서 windows 서비스에서 open-ssh-server 실행현재 사용하고 있는 사용자(windows 사용자) 가 관리자 권한을 보유 할 경우 programdata/sshd_config 파일 수정 필요기타 파일 권한 정리 필요로 인하여 scp 프로그램을 windows 환경의 intellij idea 에서 id, 비번치게끔 ide 콘솔에서 지원하지 않는거 같아. 그래서 제미니가 추천해준대로 실습 환경에서 scp 접속 단을 copy 로 그냥 퉁치는 것으로 바꿔놨어. 나처럼 windows 환경인 사람들이 있으면 혹시나 참고했으면 좋겠네. ObjectMapper, JavaTimeModule 같은 경우는 org.springframework.boot:spring-boot-starter-json 의존성 추가 필요
-
미해결AWS SAA-C03 자격증 벼락치기 - 딱 163문제로 2주만에 합격하기
31강 이미지내용에 틀린 부분이 있는 것 같습니다.
해당사진의 3번째 서브넷부분은10.10.0.16/29가 맞지않나 싶습니다.
-
해결됨제미니의 개발실무 - 커머스 백엔드 레거시와 AI 활용편
ProductOption을 통한 FindProductOption에 관한 질문
ProductOption을 fetch해 올때 DB레벨에서 where이랑 orderby를 하지 않고 애플리케이션 레벨에서 코틀린 filter와 sort를 하신 이유가 따로 있을까요? 성능상 DB에서 전체적으로 데이터를 가져오고 인메모리 작업으로 filter와 sort를 하는게 불리하지 않나 싶어서 질문을 남깁니다.
-
해결됨제미니의 개발실무 - 커머스 백엔드 레거시와 AI 활용편
상수에 관련해서 질문있습니다.
요구 사항이 자주 변경되는 것을 가정하는 프로젝트인 만큼 isUnique에 관련된 상수나 Recent day에 관한 상수를 properties로 빼서 yml에 관리하는 방식으로 구현해보았는데. 실무에서는 어떤 경우에 yml에서 관리하는 방식을 고려하고 어느 상황에 그냥 상수를 코드에 남기는지 궁금합니다.
-
미해결AWS SAA-C03 자격증 벼락치기 - 딱 163문제로 2주만에 합격하기
23강 문제4 질문드립니다.
"과도한 읽기 및 쓰기 트래픽이 몰려"라고 써있는데, 왜 답이 C가 되는지 잘 이해가 되지 않아 질문드립니다. 읽기 전용 복제본을 추가하면 쓰기 트래픽의 부하를 막을 수 있는건 아니라고 생각되는데 왜 답이 C가되나요? 혹시, 다른 답들이 애매해서 그런건가요? 아니면 읽기 트래픽을 줄일 수 있으니 쓰기트래픽이 많아도 읽기 트래픽의 부하를 줄임으로써 전체적인 트래픽의 부하가 줄어들기 때문인가요?
-
해결됨제미니의 개발실무 - 커머스 백엔드 기본편
histories() 응답에 PointHistory.id를 포함한 이유가 궁금합니다/
안녕하세요.histories() 응답에 PointHistory.id가 포함되어 있던데, 이 값을 내려주신 의도가 궁금합니다.FE에서 이 id를 직접 활용해야 하는 지점이 있는지 궁금해서요.예를 들어 포인트 이력 상세 조회나 특정 이력을 식별해야 하는 기능을 염두에 두신 걸까요?현재로서는 다른 필드들만으로도 충분하지 않나 생각되어, id를 포함하신 이유가 궁금합니다!
-
미해결AWS SAA-C03 자격증 벼락치기 - 딱 163문제로 2주만에 합격하기
S3 예상 기출 3번
문제는 생성 후 24시간 이내 자동 삭제인데 왜 정답에는 1일 후 삭제하는 수명 주기일까요 ㅜㅜ 그럼 24시간 이내가 안되는거라 생각이 들어서요
-
해결됨제미니의 개발실무 - 커머스 백엔드 기본편
SettlementTargetRepository Jquery 질문
@Query( """ SELECT new io.dodn.commerce.storage.db.core.SettlementTargetSummary( settlement.merchantId, settlement.settlementDate, SUM(settlement.targetAmount), COUNT(settlement.id), COUNT(DISTINCT settlement.orderId) ) FROM SettlementTargetEntity settlement WHERE settlement.settlementDate = :settlementDate GROUP BY settlement.merchantId, settlement.settlementDate """, ) fun findSummary(settlementDate: LocalDate): List<SettlementTargetSummary>이부분에서 where절에서 이미 settlementDate를 필터링하고 있는데 group by에서 settlementDate가 필요한 이유가 따로 있을까요? 어차피 parameter로 넘어온 settlementDate만 조회가 되는 로직이라 Group By에서는 필요가 없어보여 질문 남깁니다.
-
미해결AWS SAA-C03 자격증 벼락치기 - 딱 163문제로 2주만에 합격하기
33강 3번 문제 D번 질문
안녕하세요 강의 복습하면서 열심히 학습중입니다. 33강 문제 3번에서 퍼블릭 IP를 사용해서는 안된다는것은 인터넷 연결을 피해야한다고 생각하는데 D 번은 결국 NAT 게이트웨이를 통해 인터넷을 거쳐 S3와 통신하는거라 생각하고 있습니다. 결국 S3의 입장에서는 인터넷을 통한 통신이 들어오는거라고 생각해서요. 제가 잘못 이해한건지 알려주시면 감사합니다!
-
해결됨Next.js 마스터 클래스: Part 2 - 풀스택 아키텍처와 프레임워크 심화 (Server Actions, 캐시 혁명, 고급 라우팅)
22강 강의 영상 문의 드립니다.
안녕하세요.해당 섹션을 보니 강의 영상이 올라갈 자리로 보이나 빈 화면이 나와서요.확인 부탁드립니다 :)
-
해결됨제미니의 개발실무 - 커머스 백엔드 기본편
부가 기능을 이벤트 핸들러로 분리하는 기준이 있을까요?
addReview()를 보면 리뷰 저장 이후에 포인트를 지급하는 로직이 함께 들어가 있는데, 제 기준에서는 포인트 지급이 리뷰 작성의 핵심 기능이라기보다 부가 기능처럼 느껴졌습니다.그래서 이런 부분은 서비스 내부에서 직접 호출하기보다 이벤트를 발행하고, 별도의 핸들러에서 처리하는 방식으로 분리해도 괜찮지 않을까 궁금했습니다.(다만 제가 이걸 정말 "부가적인 책임"으로 봐도 되는지 조금 헷갈리기도 합니다.)만약 실무에서는 이런 부가적인 로직을 서비스 메서드 안에 함께 둘지, 아니면 이벤트/이벤트 핸들러 형태로 분리할지를 어떤 기준으로 판단하시는지 궁금합니다.또는 이런 경우 이벤트 외에 다른 방식으로 설계하시는 경우도 있는지 궁금합니다.
-
해결됨Next.js 마스터 클래스: Part 2 - 풀스택 아키텍처와 프레임워크 심화 (Server Actions, 캐시 혁명, 고급 라우팅)
아래 위치에 동영상이 보이지 않습니다.
아래 위치에 동영상이 보이지 않습니다.36. 18강. [Next.js 실전] redirect() 함수로 구현하는 완벽한 동선 제어
-
해결됨Next.js 마스터 클래스: Part 2 - 풀스택 아키텍처와 프레임워크 심화 (Server Actions, 캐시 혁명, 고급 라우팅)
강의자료가 않보입니다.
아래 위치에 강의자료가 않보입니다.[강의 노트] 07강. [CS 아키텍처] 이벤트 기반 아키텍처(EDA)와 웹훅(Webhook)
-
미해결AWS SAA-C03 자격증 벼락치기 - 딱 163문제로 2주만에 합격하기
예상 기출문제 해설 중복 표기 제보
'26.01.22 버전 예상 기출 문제 PDF 238P네트워크-2 4번 문제 해설 오답 B 번이 3번 문제 해설 B 번으로 중복 표기된 것 같아요~시중 덤프문제로 공부하기 힘들어 포기했다가, 강사님 강의로 다시 공부 시작했어요.좋은 강의 감사합니다 ~
-
미해결[코드팩토리] [초급] NestJS REST API 백엔드 완전 정복 마스터 클래스 - NestJS Core
cascade 질문
cascade: true 후 createUserAndProfile의 user 안에 직접 profile을 넣고 postman에서 post (/user/profile)요청시 profile이 생성된 것처럼 보이지만get(/users) 요청 시 해당 유저는 profile이 null로 떠야하는데실습으로 post (/user/profile) 이후 get (/users) 요청하면 해당 유저가 profile 값을 가지고 있습니다. 코드를 똑같이 입력했는데 뭐가 문제일까요?
-
해결됨제미니의 개발실무 - 커머스 백엔드 레거시와 AI 활용편
null 을 많이 허용하지 않는 이유
안녕하세요~ 강의 중 강사님께서 null을 되도록 허용하지 않는 것으로 보였습니다.공감이 되었는데, CancelEntity.orderItemId 와 같은 곳에 -1 을 설정한 다거나 QnA.answer 에 Answer.EMPTY 를 설정하는 것은 어떤 장점이 있을지 궁금합니다.저는 위와 같은 경우는 해당 필드를 nullable 로 하는 것이 이 필드는 없을 수 있다는 것을 더 명확하게 나타낼 수 있다고 생각했습니다. 좋은 강의 감사합니다!
-
미해결처음하는 파이썬 백엔드 FastAPI 입문 (FastAPI부터 비동기 SQLAlchemy까지) [풀스택 Part1-2]
강의노트는 제공 안해주시는 게 맞나요?
강의 자료 다운 받아봤는데, 코드만 있네요 ㅠㅠㅠ
-
해결됨제미니의 개발실무 - 커머스 백엔드 기본편
엔티티의 pk 를 0으로 초기화하시는 이유가 있을까요??
자바에서 클래스 필드 타입을 참조타입과 원시타입의 차이를 공부하던 중에둘의 차이가 null 값이 필요하냐 필요하지 않냐로 배웠습니다..그런데 엔티티 pk의 경우에는jpa에서 새 객체와 저장된객체를 구분할 때 null 을 본다고 들었습니다.그래서 참조형 Long을 쓰는 구나 라고 생각을 정리했어요!! 헌데 코틀린으로 쓰신 코드에서는 Long타입을 선언하시고 0으로 초기화해주시는 이유가 궁금합니다!코틀린에서는 nullable하게 할순있지만 기본적으로 null이 불가능하다고 들었긴한데.. 조금 헷갈립니다!언어적인 부분에서 jpa가 다르게 동작하는것인지 아니면 제가 좀 미숙하게 이해한건지 궁금합니다!
-
미해결AWS SAA-C03 자격증 벼락치기 - 딱 163문제로 2주만에 합격하기
'18. [예상 기출문제] 1~9번 문제 풀이' 강의 화면이 저만 안보이는걸까요..?
안녕하세요!위 화면처럼 강의 영상이 안보이는데 혹시 저만 그런걸까요..?