Spring Scheduler & Async 처리 흐름 - 정기 작업과 비동기 실행 완전 정복

2025. 7. 15. 19:53Framework/Spring

1. @Scheduled - 스케줄링 처리의 핵심

 

📌기본 개념

  • @Scheduled는 정해진 주기마다 메서드를 실행하는 어노테이션이다.
  • 백그라운드에서 자동으로 실행되며 주로 배치 작업, 통계 집계, 외부 API 호출 등 반복 작업에 사용

🔧 사용 전 설정

@Configuration
@EnableScheduling
public class SchedulerConfig {
}
@Component
public class SampleScheduler {
    @Scheduled(fixedDelay = 5000)
    public void task() {
        System.out.println("5초마다 실행");
    }
}

2. 다양한 실행 옵션

속성 설명
fixedRate 메서드 시작 시점 기준 반복 (밀리초)
fixedDelay 메서드 종료 시점 기준 반복 (밀리초)
initialDealy 최초 실행 지연 시간
cron CRON 표현식 기반

 

@Scheduled(fixedRate = 10000) // 10초마다
@Scheduled(fixedDelay = 10000, initialDelay = 2000)
@Scheduled(cron = "0 0 * * * *") // 매 정시 실행

 


3. cron 표현식 완전 정리

┌───────────── 초 (0-59)
│ ┌───────────── 분 (0-59)
│ │ ┌───────────── 시 (0-23)
│ │ │ ┌───────────── 일 (1-31)
│ │ │ │ ┌───────────── 월 (1-12)
│ │ │ │ │ ┌───────────── 요일 (0-6, 일=0)
│ │ │ │ │ │
│ │ │ │ │ │
* * * * * *

 

예시:

  • 0 0/5 * * * * ->매 5분마다 실행
  • 0 0 9 * * MON-FRI -> 평일 오전 9시 실행
  • 0 0 2 1 * * -> 매월 1일 새벽 2시

4. @Async - 비동기 처리 핵심

 

✅ 기본 사용법

@EnableAsync
@Configuration
public class AsyncConfig {}

@Component
public class AsyncService {
    @Async
    public void asyncTask() {
        // 별도 스레드에서 실행
        System.out.println("비동기 작업 수행");
    }
}
  • 별도의 스레드에서 병렬로 실행 
  • 리턴값이 있는 경우 @Async + CompletableFuture<T>로 사용

⚙️ 5.  작동원리 - 프록시 기반

  • @Async는 내부적으로 Spring AOP 프록시를 사용
  • 호출자가 같은 클래스 내의 메서드를 직접 호출하면 비동기 작동하지 않음
  • 반드시 다른 Bean이 호출해야 작동함

6. @Scheduled + @Async 병렬 실행

  • 기본적으로 @Scheduled는 싱글 스레드로 작동
  • 작업이 오래 걸리면 병렬 처리 불가

✅ 병렬 실행 방법

@Scheduled(fixedRate = 1000)
@Async
public void doWork() {
    System.out.println(Thread.currentThread().getName());
}

 

⚠️ 주의

  • @EnableScheduling과 @EnableAsync 모두 선언해야 함
  • 비동기 실행 시 Exception은 별도 처리 필요

7. Custom Executor 설정 

@Configuration
@EnableAsync
public class AsyncExecutorConfig implements AsyncConfigurer {
    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(100);
        executor.setThreadNamePrefix("AsyncExecutor-");
        executor.initialize();
        return executor;
    }
}
  • Async는 여기서 정의한 Executor를 사용함

8. 예외 처리 전략

  • 비동기 작업에서 발생한 예외는 @AsyncUncaughtExceptionHandler로 처리 가능
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
    return (ex, method, params) -> {
        log.error("Async Error in {}: {}", method.getName(), ex.getMessage());
    };
}

9. 실무 적용 사례

  • 특정 시간마다 로그 정리 or 메일 발송 (@Scheduled)
  • 다량의 알림 발송 (@Async)
  • 외부 API 비동기 호출 (@Async)
  • 실시간 분석 작업 분산 처리

✅ 정리

항목 핵심 요약
@Scheduled 주기적 실행 (기본은 싱글 스레드)
@Async 별도 스레드에서 비동기 실행
병렬 처리 @Scheduled + @Async 조합 필수
실무 적용 대용량 처리, 외부 연동, 백그라운드 작업
확장 방법 Custom Executor 설정, 예외 핸들러 구성

🔜 다음 포스팅 예고

Spring Batch 핵심 개념 완전 정복 - Step, Job, Reader/Processor/Writer 구조부터 실무 적용까지