
TossPayments API 자동결제를 구현하며 매월 자동 결제를 구현하기 위해 Spring Scheduler를 도입하게 되었다. 그 과정에 대해 적어보겠다!
Tosspayments 자동결제(Billing) 과정을 간단하게 설명하자면
1. 구매자 카드 등록
2. 빌링키 발급
3. 결제 주기에 빌링키로 원하는 금액 자동결제 승인
이렇게 크게 3단계로 이루어진다. 하단 이미지는 Tosspayments에서 제공되는 결제 프로세스이다.

이때 Tosspayments에서는 자체적으로 스케줄링 기능을 제공하지 않기 때문에, 우리가 직접 스케줄링 기능을 구현해서 원하는 주기, 시점에 자동결제 승인 API를 호출해야한다.
따라서 Spring Scheduelr를 통해 자동결제 기능을 구현한 과정에 대해 간단하게 글을 적어보겠다!
@Configuration
@EnableScheduling
public class SchedulerConfig{
@Bean
public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setPoolSize(Runtime.getRuntime().availableProcessors() * 2); //cpu 코어 개수 2배로 설정
scheduler.initialize();
return scheduler;
}
}
팀 코딩 컨벤션에 따라 해당 설정 파일은 global/config에 작성하였다.
@EnableScheduling
스케줄링 기능을 활성화하는 어노테이션
setPoolSize
동시에 실행 가능한 스레드 수 지정
외부 API를 쓰는 경우에는 CPU 코어 수 *2 정도로 설정하는 것이 좋다
setThreadNamePrefix("BillingScheduler-")
스레드 이름 접두사 설정
setWaitForTasksToCompleteOnShutdown(true)
애플리케이션 종료 시 작업 완료 대기
setAwaitTerminationSeconds(30)
최대 대기 시간(초)
등의 설정들이 있기 때문에 본인 프로젝트에 맞도록 설정을 하면 된다.
@Component
@RequiredArgsConstructor
public class BillingScheduler {
private final BillingService billingService;
private final SubscriptionRepository subscriptionRepository;
//00시에 자동으로 결제 진행
@Scheduled(cron = "0 0 0 * * *", zone = "Asia/Seoul")
public void runAutoBillingTask(){
//오늘 결제일인 구독 목록 조회
List<Subscription> subscriptions =
subscriptionRepository.findByNextBillingDateAndIsActive(LocalDate.now(), true);
for(Subscription subscription:subscriptions){
if(subscription.getBillingKey() == null){
subscription.deActivatePremium(); //구독 종료
subscriptionRepository.save(subscription);
continue;
}
try{
billingService.autoPayment(subscription);
}catch(ErrorException e){
subscription.deActivatePremium();
subscriptionRepository.save(subscription);
}
}
}
}
cron 표현식
각 (분 시 일 월 요일)을 뜻하고 공백으로 구분하고 * 은 매 번을 의미한다.
즉 cron = "0 0 0 * *"은 매일 00시에 해당 로직이 실행된다는 의미이다.
zone = "Asia/Seoul"
스케줄이 동작할 시간대를 명시적으로 설정한다.
기본적으로 IntelliJ 실행 환경의 시스템 시간대를 따르지만, 서버 환경에 따라 시간대가 달라질 수 있기 때문에, 정확한 동작을 위해
"Asia/Seoul"을 명시적으로 지정하였다.
이 외에도
등의 설정들이 있기 때문에 본인 프로젝트에 맞도록 설정을 하면 된다.
이렇게 설정하면 정해진 시간대에 원하는 로직이 자동으로 실행되는 것을 확인할 수 있다.
만약 하나의 프로젝트 안에서 여러 개의 스케줄러를 운영해야 한다면, 서로 다른 시간대로 분리하는 것이 좋다.
또한 현재는 Spring Scheduler를 통해 간단한 주기적 작업을 처리하고 있지만, 이후 리팩토링 시점에 Spring Batch나 Quartz Scheduler 같은 전문적인 배치 스케줄링 시스템으로 확장하여 더 안정적이고 체계적인 자동결제 프로세스를 구현해볼 계획이다! 😁