TaskExecutor와 TaskScheduler

hoyong.eom·2024년 4월 2일
0

스프링

목록 보기
54/59
post-thumbnail

TaskExecutor와 TaskScheduler

회사에서 scheduler를 구현할 일이 생겨서 토비 책을 펼쳐보았다.
펼쳐서 공부한 김에 한번 정리해보자.

TaskExecutor와 TaskSchduler에서 말하는 Task는 java.lang.Runnable의 run()이라는 메소드를 가진 인터페이스를 구현한 독립적인 스레드에 의해서 실행되도록 의도된 오브젝트를 말한다.

즉, 독립적인 스레드 안에서 동작하도록 만들어진 오브젝트를 독립적으로 실행 가능한 작업이라는 의미로 태스크(Task)라 부른다고 한다.

스프링에서 Task를 다양한 방법(Quartz, Spring 구현, 등등)으로 실행하도록 만들어진 오브젝트 특징을 추상화한 Task 실행기라는 인터페이스가 바로 TaskExecutor라고 한다.

public interface TaskExecutor extends Excutor{
	void execute(Runnable task)
}

TaskExecutor가 추상화한 기술은 비동기적으로 독립적인 스레드에서 실행되고, 주로 스레드 풀을 사용하는 방식을 사용한다고 한다.
스프링이 직접 구현한 몇가지 TaskExecutor에는 동기화 실행 방식도 있고, 스레드 풀을 사용하지 않고 계속 새로운 스레드를 만드는 구현 방식도 있다고 한다.
하지만 실제로는 비동기 방식으로 스레드 풀을 이용해 실행되는것이 유용하게 (일반적으로) 쓰일 수 있는 Task 실행 모델이다.

  • ThreadPoolExecutor
    - 지정된 크기의 스레드 풀을 이용해서 작업 요청은 큐를 통해 관리된다. 가장 손쉽게 사용할 수 있는 대표적인 TaskExecutor이다.
  • SimpleThreadPoolTaskExecutor
    - Quartz의 SimpleThreadPool을 이용해 만들어진 Task 실행기이다. TaskExecutor 추상화 인터페이스를 통해 Quartz 스케쥴러와 독립적으로 사용되면서 동시에 Quartz의 작업에도 활용될 수 있다.

TaskScheduler

일반적으로 태스크는 일정한 간격 또는 시간 기준에 따라 실행되는 스케쥴링 방식으로 동작하는 경우가 대부분이다.
자바에는 스케쥴링 기능을 제공하는 다양한 구현 기술이 존재하며 스프링은 TaskExecutor와 마찬가지로 서비스 추상화 기법을 이용해서 스케쥴링 기술에 독립적인 사용이 가능한 추상화 서비스 인터페이스인 TaskScheduler를 제공한다.

TaskScheduler 인터페이스는 주어진 태스크를 조건에 따라 실행하거나 반복하는 작업을 수행한다. 태스크의 실행 조건은 단순히 특정 시간에 시작되도록 만들 수 있고, 일정한 간격을 두고 반복되게 할 수도 있다.
또는 Trigger 인터페이스를 ㄱ구혀해서 좀 더 유연한 실행 조건을 만들 수 도 있다.
아래의 코드는 TaskScheduler를 구현한 빈을 DI 받은 스케쥴러와 태스크가 있다면 ConTrigger를 이용해서 스케쥴링하는 코드이다.

@Autowired
TaskScheduler schduler;

Runnable task

public void startScheduler(){
	scheduler.schedule(task, new CronTrigger("0 30 4 * * MON-FRI"));
}

TaskScheduler의 주요 구현 클래스는 아래와 같다.

  • ThreadPoolTaskScheduler
    - JDK의 ScheduledThreadPoolExecutor 스케쥴러에 대한 어댑터라고 한다. ScheduledThreadPoolExecutor는 스레드 풀 방식의 태스크 실행기 기능도 함께 갖고 있다고 한다.별도의 스레드 관리 서비스를 두지 않는 경우 간편하게 사용할 수 있다.
  • TimerManagerTaskScheduler
    - commonJ의 TimerManager를 TaskScheduler로 추상화한 클래스라고 한다. 애플리케이션 레벨에서 스레드를 관리하는 게 바람직하지 않아 보인다면 CommonJ와 같은 독립적인 작업과 스케쥴 관리를 위한 서비스 사용을 고려해볼 수 있다.

애노테이션을 이용한 스케쥴링과 비동기 태스크 실행

스프링은 스케쥴링과 비동기 방식의 태스크를 간단하게 정의할 수 있는 애노테이션을 제공한다.

@Scheduled

@Scheduled는 태스크 역할을 맡을 메소드에 직접 스케쥴 정보를 애노테이션을 통해 부여해서 스케쥴이 적용되게 해준다.
@Scheduled는 세 가지종류의 트리거 설정을지원한다.

fixedDelay

이전작업이끝난시점부터일정 시간이 지난 후에 동작하도록 설정한다.시간단위는 밀리초이다. 아래의코드는 checkSystemStatus() 메소드를 1분 간격으로 실행하는 스케쥴러 설정코드이며, 1분마다 실행되는게 아니라 이전 메소드작업이 끝난후로부터 1분 후에 다음 작업이 시작된다.

@Scheduled(fixedDelay=60000)
public void checkSystemStatus(){...}

fixedRate

밀리초로 설정된 일정한 시간 간격으로 메소드가 실행되게 해준다.
fixedDelay와 다르게 이전 메소드가 호출된 시점으로 부터의 시간이다.

@Scheduled(fixedRate=60000)
public void checkSystemStatus(){...}

cron

cron 포맷을 사용해 스케쥴을 지정할 수 있다. 가장 유연하게 스케쥴을 지정할 수 있는 방법이다.

@Scheduled(cron="0 0 12 1 * MON-FRI")
public void checkSystemStatus(){...}

@Scheduled가 부여되는 메소드는 파라미터를 가 질 수 없으며 반드시 void형의 리턴 타입이어야 한다.

@Async

@Async가 부여된 메소드는 자동으로 비동기 방식으로 실행된다.
TaskExecutor를 코드로 사용하지 않고도 비동기 실행이 가능하게 해주는 편리한 애노테이션이다. 비동기로 동작하기 때문에 메소드 내의 작업이 오랜 시간 걸리더라도 메소드를 호출하면 바로 리턴된다. 메소드는 별도의 스레드에서 동작한다.
리턴 타입이 void 또는 Future 타입이어야 한다. 메소드는 다른 코드에 의해 직접 호출 되므로 파라미터는 가질 수 있다.

참고

토비의스프링에서 TaskExecutor와 TaskScheduler를 공부하여 정리한 내용입니다.

https://hyeonyeee.tistory.com/73
https://pompitzz.github.io/blog/Spring/Scheduler.html

0개의 댓글