Redis를 활용한 결제 후 자동 수취 기능 구현

결제 완료 후 일정 시간이 지나면 자동으로 수취 처리되는 기능은 전자상거래 시스템에서 흔히 요구되는 요구사항 중 하나입니다. Redis의 만료 기능과 Spring의 스케줄링을 조합하면 비교적 간단하게 이를 구현할 수 있습니다.

1. 프로젝트 의존성 설정

Spring Boot 기반의 애플리케이션에서 Redis를 사용하기 위해선 먼저 필요한 라이브러리를 포함해야 합니다. Maven 기준으로 다음과 같은 의존성을 추가합니다.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>

2. Redis 연결 정보 구성

application.yml 또는 application.properties 파일에 Redis 서버 접속 정보를 설정합니다.

spring:
  redis:
    host: localhost
    port: 6379
    timeout: 5s
    lettuce:
      pool:
        max-active: 8
        max-idle: 8

3. 주문 상태 관리 로직

주문 생성 시 Redis에 해당 주문의 상태와 타임아웃 정보를 저장합니다. 여기서는 결제 완료 후 24시간이 지나면 자동 수취 처리되도록 설계합니다.

@Service
public class PurchaseOrderService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    public void initiateOrder(String orderId, String buyerId) {
        // 주문 상태: 미수령
        stringRedisTemplate.opsForValue().set("trade:status:" + orderId, "PENDING_PAYMENT");
        // 24시간 후 만료되는 더미 키 (TTL 기반 트리거)
        stringRedisTemplate.opsForValue().set("trade:auto-receive:" + orderId, "trigger", Duration.ofHours(24));
    }

    public void onPaymentConfirmed(String orderId) {
        // 결제 완료 시 상태 업데이트
        stringRedisTemplate.opsForValue().set("trade:status:" + orderId, "PAID");
    }
}

4. 만료 감지 기반 자동 수취 처리

Redis 자체에는 키 만료 시 이벤트를 직접 실행하는 기능은 없지만, 키 만료 알림(Kafka-like expired event)을 활성화하고 이를 리스닝함으로써 실시간 반응이 가능합니다. 그러나 보다 단순한 방식으로는 주기적으로 검사하는 배치 방식도 고려할 수 있습니다.

여기서는 정기 점검 방식을 사용하며, Spring의 @Scheduled를 이용합니다.

@EnableScheduling
@Service
public class ScheduledAutoReceiptProcessor {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Scheduled(fixedDelay = 30 * 60 * 1000) // 30분 간격으로 실행
    public void processExpiredOrders() {
        Set<String> expiredKeys = stringRedisTemplate.keys("trade:auto-receive:*");
        if (expiredKeys == null || expiredKeys.isEmpty()) return;

        for (String key : expiredKeys) {
            String[] parts = key.split(":");
            String orderId = parts[3];

            String statusKey = "trade:status:" + orderId;
            String currentStatus = stringRedisTemplate.opsForValue().get(statusKey);

            if ("PAID".equals(currentStatus)) {
                // 자동 수취 처리
                stringRedisTemplate.opsForValue().set(statusKey, "RECEIVED");
                executePostReceiveActions(orderId);
            }

            // 트리거 키 삭제 (이미 만료되었으므로 명시적 제거)
            stringRedisTemplate.delete(key);
        }
    }

    private void executePostReceiveActions(String orderId) {
        // 예: 데이터베이스 상태 동기화, 포인트 적립, 알림 발송 등
        System.out.println("주문 " + orderId + " 이(가) 자동 수취 처리되었습니다.");
    }
}

5. 운영 고려 사항

  • 정확성: 만료된 키는 Redis에서 비동기적으로 체크하므로 실제 삭제 시점과 알림 수신 시점에 차이가 있을 수 있습니다. 따라서 정기 점검 주기를 서비스 요구사항에 맞게 조정해야 합니다.
  • 중복 방지: 스케줄러가 여러 인스턴스에서 실행될 수 있으므로, 분산 잠금 등을 통해 한 번만 실행되도록 보장하는 것이 좋습니다.
  • 모니터링: 자동 처리된 건에 대해 로그 또는 메트릭 수집이 필요합니다.

이 방식은 성능과 유지보수 측면에서 효과적이며, Redis의 고성능 특성을 활용하여 수천 건 이상의 주문을 효율적으로 처리할 수 있습니다.

태그: Redis Spring Boot 자동 수취 스케줄링 전자상거래

5월 31일 15:05에 게시됨