> For the complete documentation index, see [llms.txt](https://docs.sysout.co.kr/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.sysout.co.kr/web/back-end/what-is-spring-framework/etc/scheduler.md).

# Scheduler

## Spring Scheduler

스케줄러는 **정해진 주기마다 작업을 실행하는 도구**이다.\
따라서 스케줄러를 생성하기 위해서는 반드시 `주기`와 `작업`을 설정해야 한다.\
다음과 같은 작업들은 모두 스케줄러로 할 수 있는 작업에 해당한다.

* 음원 차트를 매 정각마다 갱신한다.
* 실시간 검색어를 10분마다 갱신한다.
* 매일 아침 6시에 일일 포인트 사용내역을 초기화한다.

스케줄러를 이용할 때 주의할 점은 다음과 같다.

* 주기가 짧을 수록 성능 저하의 가능성이 높아진다.
* 스케줄러에서 수행하는 작업이 복잡할수록 성능 저하의 가능성이 높아진다.
* 스케줄러를 많이 사용할수록 성능 저하의 가능성이 높아진다.

## Spring dependency

스프링에서 스케줄러를 사용하려면 다음 의존성이 필요하다.

* org.springframework.spring-task

## Spring xml setting

스프링에서 스케줄러를 사용하려면 두 가지 방법을 고려할 수 있다.

* 생성된 bean을 xml 설정에서 task 설정으로 등록하는 방법
* xml 설정에 활성화 태그만 작성해둔 뒤 annotation으로 등록하는 방법

이 문서에서는 두 번째 방법을 사용한다.

### namespace 설정

우선 xml 설정에서 `task` 관련 설정을 수행할 수 있도록 namespace를 추가해야 한다.\
다음 이미지를 참고하여 `root-context.xml` 에 설정한다.

![좌측 하단의 Namespaces 탭 선택](/files/-MdFn_N-LvK6PRszlK4X)

![task namespace를 선택하여 활성화](/files/-MdFneA1A0EEUliyikod)

![namespace 활성화 확인](/files/-MdFniOscaPmddxeYYEi)

> root-context.xml

```
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:task="http://www.springframework.org/schema/task"
	xsi:schemaLocation="http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.3.xsd
		http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
	
    <!-- task 관련 annotation 활성화 설정 -->
	<task:annotation-driven/>
		
</beans>

```

`<task:annotation-driven/>` 태그를 작성하여 task 관련 annotation을 활성화 처리한다.\
이후 우리가 등록하는 task들을 자동으로 스캔하여 찾아준다.

## Scheduler 등록

설정을 마쳤다면 스케줄러를 생성하고 등록해본다.\
스케줄러는 `Service` 형태로 생성 및 등록할 것이며 다른 형태여도 무방하다.

> ScheduleService.java

```
public interface ScheduleService {
	void work();
}
```

> ScheduleServiceImpl.java

```
@Service
@Slf4j
public class ScheduleServiceImpl implements ScheduleService{
    @Override
    @Scheduled(fixedRate = 1000)
    public void work() {
        log.info("work 메소드 실행");
        log.info("현재시각 = {}", LocalDateTime.now());
    }
}
```

서버를 이용하여 현재 프로젝트를 실행해보면 1초 간격으로 현재시각이 출력되는 것을 확인할 수 있다.\
`<task:annotation-driven/>` 설정을 해두었기 때문에 `@Scheduled` 애노테이션을 찾아서 자동으로 시작 시 옵션에 맞게 구동되도록 해주는 것이다.

## @Scheduled 옵션

`@Scheduled`에는 다음과 같은 옵션을 사용할 수 있다. [API](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/scheduling/annotation/Scheduled.html)

* `cron` : unix 계열에서 사용하는 cron과 같은 표현식 형태로 주기를 설정
* `fixedDelay` : 작업 종료와 재시작 사이의 간격을 **밀리초(ms)** 단위로 설정
* `fixedDelayString` : 작업 종료와 재시작 사이의 간격을 [java.time.Duration](https://docs.oracle.com/javase/8/docs/api/java/time/Duration.html?is-external=true#parse-java.lang.CharSequence-) 규격에 맞게 설정
* `fixedRate` : 작업 시작과 시작 사이의 간격을 **밀리초(ms)** 단위로 설정
* `fixedRateString` : 작업 시작과 시작 사이의 간격을 [java.time.Duration](https://docs.oracle.com/javase/8/docs/api/java/time/Duration.html?is-external=true#parse-java.lang.CharSequence-) 규격에 맞게 설정
* `initialDelay` : 작업의 최초 시작 전의 대기 간격을 **밀리초(ms)** 단위로 설정
* `initialDelayString` : 작업의 최초 시작 전의 대기 간격을 [java.time.Duration](https://docs.oracle.com/javase/8/docs/api/java/time/Duration.html?is-external=true#parse-java.lang.CharSequence-) 규격에 맞게 설정
* `zone` : cron 표현식을 적용시킬 타임 지역을 설정

## cron 표현식

cron 표현식의 사용 형태에 대해 살펴본다.

### cron 표현식 형식

```
@Schedule("초설정  분설정  시간설정  날짜설정  월설정  요일설정")
```

또는

```
@Schedule("초설정  분설정  시간설정  날짜설정  월설정  요일설정  연도설정")
```

일반적으로 연도를 설정할 일은 거의 없다.

### 주요 기호 설명

cron 표현식에서 사용하는 주요 기호들은 다음과 같다.

* `*`
  * 전체(All)을 의미
* `?`
  * 아무때나(Any)를 의미
  * 일, 요일 자리에만 사용 가능
  * 일이나 요일에 패턴이 지정될 경우 반대쪽은 ? 로 설정한
* `,`
  * 값을 여러 개 지정할 때 사용
  * `11, 15, 20`으로 설정하면 3개가 설정
* `-`
  * 범위 지정 기호
  * `10-20` 은 10부터 20까지 범위를 설정
* `/`
  * 주기 설정
  * `*/3` 은 해당 항목을 3번마다 실행하도록 설정
* `L`
  * 마지막 날
* `W`
  * 가장 가까운 영업일(월-금)
* `#`
  * 주차 지정
  * `3#2`는 2주차 3(수요일)을 의미

### cron 표현식 예시

@Schedule(cron="") 안에 사용할 수 있는 표현식과 그에 대한 해석은 다음과 같다.

* `* * * * * *`
  * \*초 \*분 \*시 \*일 \*월 \*요일
  * 매 초 간격으로 실행
* `*/1 * * * * *`
  * 1초마다 \*분 \*시 \*일 \*월 \*요일
  * 매 1초 간격으로 실행
* `*/2 * * * * *`
  * 2초마다 \*분 \*시 \*일 \*월 \*요일
  * 매 2초 간격으로 실행
* `10,20 * * * * *`
  * 10,20초 \*분 \*시 \*일 \*월 \*요일
  * 매분 10초와 20초에 한 번씩 실행
* `10-20 * * * * *`
  * 10\~20초 \*분 \*시 \*일 \*월 \*요일
  * 매분 10초부터 20초 사이에 1초 간격으로 실행
* `0 * * * * *`
  * 0초 \*분 \*시 \*일 \*월 \*요일
  * 매분 0초에 실행(1분마다)
* `0 */1 * * * *`
  * 0초 1분마다 \*시 \*일 \*월 \*요일
  * 1분마다 0초에 실행
* `0 */5 * * * *`
  * 0초 5분마다 \*시 \*일 \*월 \*요일
  * 5분마다 0초에 실행
* `0 0 * * * *`
  * 0초 0분 \*시 \*일 \*월 \*요일
  * 매 시 정각에 실행
* `0 0 */2 * * *`
  * 0초 0분 2시간마다 \*일 \*월 \*요일
  * 매 2시간마다 정각에 실행
* `0 0 6 * * *`
  * 0초 0분 6시 \*일 \*월 \*요일
  * 매일 아침 6시 정각에 실행
* `0 0 6 * * W`
  * 0초 0분 6시 \*일 \*월 수요일
  * 매주 수요일 아침 6시 정각에 실행
* `0 0 6 L * ?`
  * 0초 0분 6시 마지막날 \*월 요일무관
  * 매월 마지막날 아침 6시 정각에 실행
* `0 0 6 ? * 4L`
  * 0초 0분 6시 아무날 매월 마지막수요일
  * 매월 마지막 수요일 아침 6시 정각에 실행
* `0 0 6 ? * 4#3`
  * 0초 0분 6시 아무날 매월 3번째수요일
  * 매월 3주차 수요일 아침 6시 정각에 실행
