작업열 토큰의 만료 이벤트 처리하기

2025. 5. 10. 22:39·Project/티켓핑

1. 작업열 토큰 TTL 도입

현재의 대기열 시스템은 은행 창구 방식에서 모티브를 얻어 사용자가 예매를 완료할 때마다 대기열에서 작업열로 한 명씩 이동하고 있다. 단 이러한 방식은 작업열에서 사용자가 예매를 하지 않으면 순환이 이루어지지 않는다는 문제점이 있다.

 

따라서 사용자가 작업열로 이동 시에는 Redis에 TTL과 함께 토큰을 저장해 일정 시간 이후 작업열에서 토큰이 삭제되어 대기열의 순회가 이루어지도록 설계해보기로 한다.

 


2. 작업열 이동 스케줄러

이에 토큰의 만료 상태를 어플리케이션이 알 수 있는 방법들에 대해 고민해보았는데, 첫 번째로 주기적으로 현재 작업열에 저장된 토큰 수를 세고 여유가 있는 만큼 대기열에서 작업열로 이동시키는 Job 스케줄러를 사용하는 것이었다.

 

TokenTransferScheduler

@Scheduled(fixedRateString = "${scheduler.queue-transfer-rate}")
public void processScheduledQueueTransfer() {
    workingQueueService.processQueueTransfer();
}

 

WorkingQueueService

public void processQueueTransfer() {
    // 작업열 인원 여유 확인
    AvailableSlots availableSlots = workingQueueRepository.countAvailableSlots(CountAvailableSlotsCommand.create());
    if (availableSlots.isLimited()) {
        return;
    }

    // 여유 있으면 대기열 -> 작업열 이동
    long count = availableSlots.getCount();
    waitingQueueRepository.retrieveTopWaitingTokens(RetrieveTopWaitingTokensCommand.create(count)).stream()
        .toList()
        .forEach(waitingToken -> {
        	WorkingQueueToken workingQueueToken = waitingToken.toWorkingQueueToken();
            workingQueueRepository.enqueueWorkingToken(CacheWorkingTokenCommand.create(workingQueueToken));
            waitingQueueRepository.dequeueWaitingToken(DequeueWaitingTokenCommand.create(waitingToken));
    });
}

 

 

스케줄러는 분산 환경에서 여러 인스턴스를 사용할때 중복으로 실행되기 때문에 문제가 될 수 있다. 이에 대한 해결책으로 한 인스턴스에서만 스케줄러가 동작하게 해줄 잠금 장치가 필요하다.

 


3. ShedLock 도입하기

ShedLock은 스케줄링 작업에 대해 잠금을 설정함으로서, 여러 인스턴스가 동일한 주기로 실행되는 작업을 중복 실행하지 않도록 보장한다. 구현이 간단하며 TTL 기반의 잠금으로 작업이 실패하거나 시간이 초과될 경우 다른 인스턴스가 재시도할 수 있게 한다.

 

종속성 추가

implementation 'net.javacrumbs.shedlock:shedlock-spring:5.10.0'
implementation 'net.javacrumbs.shedlock:shedlock-provider-redis-spring:5.10.0'

 

ShedLockConfig

@Configuration
@EnableSchedulerLock(defaultLockAtMostFor = "10m") // 기본 잠금 최대 시간 설정
public class ShedLockConfig {
    @Bean
    public LockProvider lockProvider(RedisConnectionFactory connectionFactory) {
        return new RedisLockProvider(connectionFactory);
    }
}

 

TokenTransferScheduler

다음과 같이 크론작업을 실행할 메서드에 어노테이션을 등록하면 끝이다.

  • lockAtMostFor: 최대 n초 동안 잠금 유지.
  • lockAtLeastFor: 최소 n초 동안 잠금 유지.
@Scheduled(fixedRateString = "${scheduler.queue-transfer-rate}")
@SchedulerLock(name = "processScheduledQueueTransfer", lockAtMostFor = "5s", lockAtLeastFor = "5s")
public void processScheduledQueueTransfer() {
    System.out.println("Scheduled Job Process!!!");
    workingQueueService.processQueueTransfer();
}

 

결과

다음과 같이 2개의 인스턴스 실행시에 한쪽에서만 스케줄링 작업을 실행하는 것을 확인할 수 있다.

 

 

 

 

'Project > 티켓핑' 카테고리의 다른 글

Redis Cluster 구축하기  (0) 2025.06.03
WebFlux 전환하기  (0) 2025.05.12
대기열 진입 동시성 문제 해결하기  (0) 2025.05.12
작업열 토큰의 만료 이벤트 처리하기 2  (0) 2025.05.10
대기열 시스템 구상하기  (0) 2025.05.10
'Project/티켓핑' 카테고리의 다른 글
  • WebFlux 전환하기
  • 대기열 진입 동시성 문제 해결하기
  • 작업열 토큰의 만료 이벤트 처리하기 2
  • 대기열 시스템 구상하기
nicky777
nicky777
  • nicky777
    Nicky Dev
    nicky777
  • 전체
    오늘
    어제
    • 분류 전체보기 (19)
      • Project (9)
        • 티켓핑 (9)
      • TroubleShooting (3)
      • Programming (0)
        • Java (0)
        • Spring (0)
      • CS (7)
        • 데이터베이스 (6)
        • 네트워크 (1)
        • 운영체제 (0)
        • 자료구조 (0)
      • 회고 (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

    • Contact
  • 인기 글

  • 태그

    materialized view
    샤딩
    HTTP
    리플리케이션
    유일키 생성 전략
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
nicky777
작업열 토큰의 만료 이벤트 처리하기
상단으로

티스토리툴바