목록Spring (17)
영호
들어가면서,최근에 같이 우테코를 수료한 지인과 각자 실무를 하면서 기본기를 다시 다지기 위해 Spring 스터디를 시작했습니다. 스터디원이 ConfigurationProperties 관련해 흥미로운 점을 알려줬고, 관련해서 조금 더 파본 내용을 간단하게 정리한 글입니다.실험을 진행한 환경은 Spring Boot 3.x 버전입니다. 궁금한 점꼭 설정 파일의 key 값과 java 코드의 필드명이 같아야 될까? HikariConfig 를 보면 maxPoolSize 란 필드가 있습니다. 그러나 설정파일 에서는 maximum-pool-size 키 값을 사용해 우리가 원하는 값을 주입 해줍니다. 즉, 설정 파일의 key 값과 자바 코드의 필드명이 달라도 매핑이 됩니다. 그래서 이를 확인해보기 위해 직접 코드를 쳐봤..
PR 링크: 링크들어가면서진행했던 프로젝트에서 이벤트를 기반으로 핵심 도메인 로직과 이에 따른 부가로직을 이벤트로 분리하였습니다. 그러나 기존의 구조에선 도메인 완료 이벤트에 따른 부가로직의 수행까진 보장하지 못합니다. 핵심 도메인 로직: 쿠폰에 스탬프 적립부가 로직: 스탬프 적립 시 방문 기록 저장기존 구조2번 과정(방문 기록 저장)이 실패하면 스탬프는 적립 되었지만 이에 해당하는 방문 기록이 없어져 데이터 정합성이 틀어집니다. 즉, 스탬프 적립 이벤트가 유실됩니다.문제 상황[도메인 로직 완료 이벤트 유실]위에서 설명했듯이 스탬프 적립 이벤트에 따른 부가기능을 수행하는 로직 실패 시 데이터 정합이 틀어지는 문제가 존재합니다. 스탬프 적립 시 부가로직은 스탬프 적립 알림, 방문 기록 추가 등이 있습니다..
멀티모듈로 분리한 이유 기존 프로젝트는 단일모듈로 구성되어 있어 코드 변경 시 전체 코드가 컴파일, 배포되는 구조입니다. 현재 프로젝트에서는 크게 2가지 영역이 있습니다. 주기적으로 외부 api 를 호출해 주차장 잔여 좌석을 갱신하는 스케줄러 spring mvc 를 활용한 어플리케이션 코드 스케줄러의 코드 변경은 어플리케이션 코드에 전혀 영향이 없습니다. 그러나 단일 모듈 구조에서는 스케줄러 코드가 변경되어도 전체 코드가 컴파일, 배포 됩니다. 현재 단일 모듈의 단점 스케줄러 코드의 변경으로 전혀 영향이 없는 어플리케이션 코드도 재배포 됩니다. 변경 주기가 다른 스케줄러, 어플리케이션 코드가 항상 같이 재배포되는 구조입니다. CI 속도가 불필요하게 오래 걸린다. 스케줄러 코드 변경으로 인해 전체 코드 테..
들어가면서 프로젝트를 진행하면서 인증코드를 redis 로 관리했습니다. 인증코드는 3분이란 유효시간이 있고 유효시간이 지난 인증코드로 인증 요청을 하면 실패해야 합니다. redis 는 메모리 기반이기 때문에 유효하지 않은 데이터는 제거하여 유효한 데이터만 저장하고 싶었기 때문에 만료된 인증코드를 어떻게 바로바로 제거할지 고민한 과정을 포스팅 할 예정입니다. redis 의 Set ex 파라미터 활용 redis 에는 다양한 command 가 있고, 그 중 key 를 저장하면서 만료시간을 설정할 수 있습니다. redis 의 ttl 만료된 키 삭제 메커니즘 redis 는 만료된 키를 삭제하는 2가지의 메커니즘이 있습니다. 만료된 key 접근 시 삭제 일정 주기로 ttl 이 설정된 키를 선정해 만료된 key 를 ..
들어가며,전에 참여했던 카페 쿠폰 서비스의 쿠폰에 스탬프를 적립하는 로직에서 동시성 이슈를 발견하여 이를 해결하기 위해 고민한 과정을 정리하려고 합니다.현재 문제점방어로직이 없다스탬프 적립 요청 시 {어느 쿠폰}에 {몇 개의 스탬프}를 적립 할지, 인증 토큰에 대한 인자만 받고 있습니다. 이로 인해, 네트워크 지연 등에 대한 재시도로 인해 동일한 쿠폰에 대한 스탬프 적립 요청이 2번 들어오면 2배의 스탬프가 적립됩니다. 즉, 중복 적립 문제가 발생합니다.기존 API 대략적인 구조POST coupon/{couponId} BODY int: stampCount원하는 결과흔히 말하는 동시성, 따닥 이슈 발생 시 하나의 요청만 유효하게 처리하길 원했습니다. 이를 만족하기 위해 어떤 고민을 했는지 작성해보겠습니다..
들어가면서, 우테코 프로젝트에서 @TransactionalEventListener 를 사용할 때 READ 는 되는데 CUD 쿼리가 발생하지 않는 문제를 겪었다. 그래서 이에 대한 원인에 대해 공부한 과정을 정리 해볼 예정이다. 트랜잭션 생성 과정과 커밋 과정 REQUIRED, REQUIES_NEW 옵션의 트랜잭션 생성 과정 물리 트랜잭션, 논리 트랜잭션 커밋 과정 각각에 대한 자세한 내용은 링크에 있습니다. 간단하게 요약하자면, 아래와 같은 흐름으로 진행됩니다. 트랜잭션 생성 시 스레드 로컬에 트랜잭션 관련 자원이 있으면 기존 트랜잭션이 있다고 판단. REQUIRED 옵션은 새로운 트랜잭션을 논리 트랜잭션으로 생성 REQUIRES_NEW 는 스레드 로컬에 자원이 있어도 새로운 물리 트랜잭션으로 생성 이후..
들어가면서, 프로젝트 도중, 아래의 요구사항을 구현하면서 @TransactionalEventListner 를 사용해 기존 코드의 문제점이었던 코드의 유지보수성과 불필요한 로직의 트랜잭션을 제거한 과정을 기록하려고 한다. 스탬프 적립이 정상적으로 완료되면, 슬랙으로 알림을 보낸다. 알림 발송에 실패해도 스탬프 적립이 롤백되어선 안된다. 기존 코드 @Transactional public void createStamp(StampCreateDto stampCreateDto) { // 스탬프 적립 전 여러 검증 코드 coupon.accumulate(earningStampCount); // 슬랙 API 호출 } 기존 코드의 문제점 기존 코드는 아래와 같은 문제점이 있다고 판단했다. 외부 API 와 비즈니스 로직이 ..
들어가면서, 트랜잭션 전파 옵션에는 REQUIRED, REQUIRES_NEW 등등이 있다. 그 중에서 이번에는 REQUIRED, REQUIRES_NEW 옵션일 때 트랜잭션 생성 과정에 대해 알아볼 예정이다. REQUIRED 는 어떻게 기존 트랜잭션이 존재하면서 해당 트랜잭션에 참여하고, 없으면 새로운 트랜잭션을 만들까? REQUIRES_NEW 는 어떻게 매번 새로운 트랜잭션을 만들까? 이 부분에 대해 알아볼 때 핵심적인 기능을 하는 클래스는 AbstractPlatformTransactionManager, JpaTransactionManager, TransactionSynchronizationManager 가 있다. 이 클래스들이 기존 트랜잭션이 있는지 확인한다. 없으면 새로운 트랜잭션 설정을 해주고, 기..