네임드 락을 활용한 동시성 제어동시성 문제 - 중복 저장@Componentclass SubscribeWorkbookUseCase( private val subscriptionDao: SubscriptionDao, private val applicationEventPublisher: ApplicationEventPublisher,) { @Transactional fun execute(useCaseIn: SubscribeWorkbookUseCaseIn) {belljundev.tistory.com 최근 AOP에 대해 다시 공부하며 AOP와 네임드 락을 활용하여 중복 구독 방지를 위해 구현하였던 LockAspect가 문제가 있지 않을까? 하는 생각을 하였습니다.AOP를 다시 공부하기 이전 제가 생각하였던 기존 ..
모든 스레드가 락을 동일한 순서로 확보하려 할 때 데드락이 발생할 수 있는데, 여기에서 락을 확보하는 순서는 전적으로 메소드를 호출하는 인자의 순서에 달렸다.따라서 두 개의 스레드가 메소드를 동시에 호출하되, 한쪽 스레드는 X에서 Y로의, 다른 쪽 스레드는 Y에서 X로 호출될 때, 데드락이 발생한다. public void transferMoney(Account fromAccount, Account toAccount, DollarAmount amout) { synchronized (fromAccount) { synchronized(toAccount) { // ... } }}위와 같이 중첩된 구조에서 락을 가져가는 상황에서 데드락을 찾아낼 수 있다.락을..
프로듀서-컨슈머 패턴은 '해야 할 일' 목록을 가운데에 두고 작업을 만들어 내는 주체와 작업을 처리하는 주체를 분리하는 설계 방법이다. 프로듀서-컨슈머 패턴을 사용하는 작업을 만들어 내는 부분과 작업을 처리하는 부분을 완전히 분리할 수 있기 때문에 개발 과정을 좀 더 명확하게 단순화시킬 수 있고, 작업을 생성하는 부분과 처리하는 부분이 각각 감당할 수 있는 부하를 조절할 수 있다는 장점이 있다. 프로듀서-컨슈머 패턴을 적용해 프로그램을 구현할 때 블로킹 큐를 사용하는 경우가 많다. 예를 들어 프로듀서는 작업을 새로 만들어 큐에 쌓아두고, 컨슈머는 큐에 쌓여 있는 작업을 가져다 처리하는 구조다. 프로듀서는 어떤 컨슈머가 몇 개나 동작하고 있는지 전혀 신경 쓰지 않을 수 있다. 단지 새로운 작업 내용을 만들..
최근 프로젝트를 진행하며 SQS를 사용하여 이벤트를 다룰 기회가 있어 해당 구현을 글로 남겨 보려 합니다.SQS 설정스프링에서 SQS를 사용을 지원하는 의존성은 spring-cloud-aws-messaging와 spring-cloud-aws-starter-sqs 두 가지가 존재합니다.레퍼런스의 경우 spring-cloud-aws-messaging 조금 더 많이 존재하였지만 저는 aws-starter-sqs를 선택하였습니다.그 이유는 mvn 저장소에서 해당 의존성의 개발 상황을 확인해 본 결과 spring-cloud-aws-messaging는 2021년 이후 더 이상 업데이트가 없는 반면, aws-starter-sqs는 지금까지 꾸준히 업데이트되고 있었기 때문입니다. 의존성dependencies { ..
이벤트 자동 발행EventPublishingRepositoryProxyPostProcessorspring-data-commons 라이브러리의 EventPublishingRepositoryProxyPostProcessor는 CrudRepository.save(Object)와 CrudRepository.delet(Object) 메서드를 인터셉트하여 @DomainEvent를 발행하고 @AfterDomainEventPublication 어노테이션이 붙은 메서드를 실행하는 MethodInterceptor를 등록합니다.@DomainEvent와 @AfterDomainEventPublication를 직접 선언하거나 AbstractAggregateRoot를 상속하는 방식으로 이벤트를 다루는 객체는 자유롭게 만들 수 있지..
이벤트 모듈 설계 다이어그램Eventabstract class Event( val eventId: String, val eventTime: LocalDateTime, )eventId와 eventTime은 필수로 가질 수 있도록 정의하였습니다. @EventDetails@Target(AnnotationTarget.CLASS) @Retention(AnnotationRetention.RUNTIME) @DomainEvent annotation class EventDetails( val outBox: Boolean = false, )Event 클래스가 비즈니스 로직을 처리하는 과정에서 필요하지 않은 정보를 위한 어노테이션입니다.outBox: 해당 이벤트가 외부까지 전달되어야 하는..