[Project] 2차 프로젝트 - 자동 반납 기능 → @Scheduled 사용

김호정's avatar
Oct 25, 2024
[Project] 2차 프로젝트 - 자동 반납 기능 → @Scheduled 사용
 
서버가 켜져 있을 때 자동으로 매서드를 실행시키고 싶을 때
 
여러가지 방법을 사용할 수 있다.
 
💡
Spring에서 스케줄링 작업을 설정하는 방법 중 하나로 @Scheduled 애노테이션을 사용하는 방법은 매우 편리하고 간단한 방법입니다. 하지만 이 방법에는 장점과 단점이 모두 존재합니다. 또한, @Scheduled 외에도 스케줄링을 설정하는 다른 방법들이 있습니다.

@Scheduled 애노테이션을 사용하는 이유 (장점)

  1. 간편한 설정:
      • @Scheduled 애노테이션을 메서드에 붙이는 것만으로 손쉽게 주기적인 작업을 설정할 수 있습니다. 추가적인 설정 파일이나 복잡한 구성 없이 바로 사용할 수 있습니다.
        • java 코드 복사 @Scheduled(cron = "0 0 0 * * *") // 매일 자정에 실행 public void autoReturnBooks() { // 작업 내용 }
  1. 다양한 스케줄링 옵션 제공:
      • @Scheduled는 다양한 스케줄링 방법을 제공합니다.예시:
        • fixedDelay: 이전 작업이 끝난 후 일정 시간 지연 후 다음 작업 실행.
        • fixedRate: 이전 작업이 시작된 시점으로부터 일정 간격으로 작업 실행.
        • cron: cron 표현식을 사용하여 스케줄을 설정.
        • java 코드 복사 @Scheduled(fixedDelay = 5000) // 5초마다 실행 @Scheduled(fixedRate = 10000) // 10초마다 실행
  1. 빠른 테스트와 유지보수:
      • 복잡한 설정 없이 간단히 메서드에 애노테이션을 추가해 테스트하거나 수정할 수 있어 유지보수가 용이합니다.
  1. 멀티 스레드 지원:
      • 여러 개의 스케줄러가 동시에 실행되더라도 스프링의 TaskExecutor가 이를 관리해 주므로 멀티 스레드 환경에서 잘 동작합니다.

@Scheduled 애노테이션을 사용하지 말아야 할 이유 (단점)

  1. 복잡한 스케줄 관리에 적합하지 않음:
      • 단순한 작업에는 적합하지만, 동적 스케줄 변경, 여러 서버 간의 작업 분배, 작업 실패 시 재시도 같은 복잡한 스케줄링 요구 사항에는 적합하지 않습니다.
      • 주기적으로 변경되거나 외부 시스템과 연동된 스케줄 설정이 필요할 경우 불편할 수 있습니다.
  1. 클러스터 환경에서 문제:
      • 여러 인스턴스(서버)가 있는 클러스터 환경에서는 모든 인스턴스에서 같은 스케줄이 실행될 수 있습니다. 이로 인해 중복 작업이 발생하거나 리소스가 낭비될 수 있습니다.
      • 예를 들어, 스케줄링이 단일 인스턴스에서만 실행되어야 할 경우 @Scheduled는 직접적으로 이를 제어할 방법이 없습니다.
  1. 스케줄링 변경이 불편:
      • 스케줄 변경을 위해서는 코드를 수정한 후 재배포해야 합니다. 즉, 스케줄 주기를 동적으로 변경하는 것이 불가능합니다.
  1. 상태 저장이 불가능:
      • @Scheduled 방식은 상태 저장이 어렵고, 스케줄의 실행 결과를 기록하거나 실패 시 재시도 등의 로직을 구현하기 어렵습니다.

스케줄링을 설정하는 다른 방법

  1. Quartz Scheduler:
      • Quartz는 매우 강력하고 유연한 스케줄링 라이브러리입니다. @Scheduled와 달리, Quartz는 클러스터링, 작업 재시도, 영구 저장, 복잡한 스케줄 관리 등 다양한 기능을 제공합니다.
        • 장점:
        • 분산 환경에서도 안정적으로 스케줄을 관리할 수 있습니다.
        • 스케줄 작업의 영속성(작업 스케줄을 DB에 저장 가능)을 지원하며, 작업이 중단되거나 실패했을 때 재시도할 수 있는 기능이 있습니다.
        • 다양한 트리거(시간 조건)를 지원하여 매우 세밀한 스케줄 관리가 가능합니다.
        • 단점:
        • 복잡한 설정과 추가적인 의존성 관리가 필요합니다.
        • 설정과 코드가 복잡해질 수 있으므로 간단한 작업에는 과도할 수 있습니다.
        • 예시:
          java 코드 복사 @Bean public JobDetail jobDetail() { return JobBuilder.newJob(MyJob.class) .withIdentity("myJob") .storeDurably() .build(); } @Bean public Trigger trigger() { return TriggerBuilder.newTrigger() .withIdentity("myTrigger") .withSchedule(CronScheduleBuilder.cronSchedule("0 0 12 * * ?")) .forJob(jobDetail()) .build(); }
  1. Spring TaskScheduler:
      • Spring에서 제공하는 TaskScheduler 인터페이스를 사용하면 @Scheduled 애노테이션 없이 프로그래밍 방식으로 스케줄을 관리할 수 있습니다.
      • 동적으로 스케줄을 변경하거나 실행할 수 있는 장점이 있습니다.
        • 장점:
        • 동적으로 작업을 추가하거나 삭제할 수 있습니다.
        • 더 많은 제어권을 제공하며, @Scheduled보다 유연한 방식으로 스케줄을 관리할 수 있습니다.
        • 단점:
        • 코드가 더 복잡해질 수 있습니다.
        • 예시:
          java 코드 복사 @Bean public TaskScheduler taskScheduler() { return new ConcurrentTaskScheduler(); // 기본 TaskScheduler 구현체 } public void scheduleTask() { taskScheduler().schedule(new RunnableTask(), new CronTrigger("0 0 0 * * *")); }
  1. Externally Managed Schedulers:
      • Kubernetes CronJobs 또는 AWS Lambda와 같은 외부 시스템의 스케줄링 기능을 사용하여 서버 외부에서 작업을 스케줄링할 수 있습니다.
      • 이를 통해 서버에 부담을 주지 않고 스케줄을 관리할 수 있으며, 관리 도구를 사용해 쉽게 모니터링할 수 있습니다.
      장점:
      • 클러스터 환경이나 서버 리소스를 최적화할 수 있으며, 외부 시스템에서 쉽게 관리할 수 있습니다.
      • 서버에 종속적이지 않고, 분산 시스템에 적합한 스케줄링을 할 수 있습니다.
      단점:
      • 외부 도구와의 통합이 필요하므로 추가적인 설정이나 복잡성이 있을 수 있습니다.

결론:

  • @Scheduled는 간단한 스케줄 작업에 적합하고, 코드 수정 없이 빠르게 주기적 작업을 설정하는 데 유용합니다.
  • 그러나 복잡한 스케줄링 요구 사항이 있거나 클러스터링 환경에서 안정적인 작업 관리가 필요할 경우에는 Quartz나 외부 스케줄러를 사용하는 것이 더 적합합니다.
  • Spring의 TaskScheduler를 사용하면 동적으로 스케줄 작업을 추가할 수 있어 유연한 스케줄링 관리가 가능합니다.
 
Quartz 사용을 고려해보았지만
 
지금 우리 프로젝트에서 스케줄 작업을 하는건 자동반납 기능밖에 없고
 
개발 기간이 짧아 빠르게 테스트와 유지보수가 가능해야 했기 때문에
 
Spring 프레임워크에 내장된 @Scheduled 를 사용해보았다. ( ← Spring의 Task 모듈에서 제공 )
 
 
어노테이션 사용을 위해
 
notion image
 
  1. 먼저 애플리케이션의 설정 클래스에 @EnableScheduling 어노테이션 추가
 
 
 
notion image
 
  1. 스케줄링할 메서드에 @Scheduled 어노테이션 붙이기
 
@Scheduled(cron = "0 0 0 * * *")
→ 자정에 실행시키도록 하는 cron이 있어서 이걸 사용했다.
 
notion image
 
  1. application.properties 파일에 서버 측에서 사용하는 기본 시간대를 서울로 설정하는 옵션 추가.
( → 스케줄링 작업 시, spring.mvc.timezone을 설정하지 않으면, 기본적으로 UTC 시간대가 적용되어서
데이터 베이스에 현재 한국/서울 시간이 저장되지 않는다. ) 아니면
💡
spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;MODE=MySQL;INIT=SET TIMEZONE 'Asia/Seoul'
 
이렇게 H2 데이터베이스에 시간대를 명시적으로 지정해 줄 수도 있다.
 
  • 추가 ) spring.jackson.time-zonespring.mvc.timezone 의 차이
 
💡
spring.jackson.time-zonespring.mvc.timezone 의 차이
Spring Boot의 application.properties 파일에서 설정하는 두 가지 속성인 spring.jackson.time-zonespring.mvc.timezone는 각각 다른 용도로 사용되며, 주로 시간대(Time Zone)를 다루는 방법에서 차이가 있습니다. 이 두 속성의 역할을 구체적으로 살펴보겠습니다:

1. spring.jackson.time-zone

  • 역할: JSON 직렬화 및 역직렬화 시 Jackson 라이브러리가 사용할 시간대를 설정하는 옵션입니다.
  • 적용 범위: 이 설정은 주로 HTTP 요청/응답 바디에서 시간 데이터를 직렬화하거나 역직렬화할 때, 즉 JSON 형식의 데이터를 주고받을 때 적용됩니다.
  • 사용 시점: 서버에서 Date, LocalDateTime 같은 시간 데이터를 JSON으로 변환하거나 JSON 데이터를 시간 객체로 변환할 때, 지정된 시간대로 처리합니다.
    • properties 코드 복사 spring.jackson.time-zone=Asia/Seoul
      이 설정을 사용하면 서버가 JSON으로 응답을 보낼 때 Asia/Seoul 시간대를 기준으로 시간 데이터를 직렬화하며, 클라이언트로부터 받은 시간 데이터도 해당 시간대로 역직렬화하게 됩니다.

2. spring.mvc.timezone

  • 역할: Spring MVC에서 서버 측에서 사용하는 기본 시간대를 설정하는 옵션입니다.
  • 적용 범위: 이 설정은 Spring MVC에서 컨트롤러가 처리하는 요청에서 날짜와 시간을 다룰 때 사용됩니다. 주로 웹 애플리케이션 전반에서 시간대를 다룰 때 기본적으로 사용할 시간대를 지정합니다.
  • 사용 시점: 서버가 사용자 요청을 처리할 때, 또는 @RequestParam, @ModelAttribute 같은 방법으로 시간 관련 데이터를 받아 처리하는 곳에서 이 시간대를 기준으로 처리하게 됩니다.
    • properties 코드 복사 spring.mvc.timezone=Asia/Seoul
      이 설정을 사용하면 Spring MVC 애플리케이션의 모든 시간대 관련 작업에서 Asia/Seoul을 기본으로 적용합니다. 예를 들어, 사용자가 시간을 입력하여 폼을 제출할 때 이 시간대가 기준이 됩니다.

차이점 요약

  • spring.jackson.time-zone: JSON 직렬화 및 역직렬화에서 Jackson이 사용할 시간대를 설정합니다. 주로 API 통신 시 JSON 형태의 데이터에 적용됩니다.
  • spring.mvc.timezone: Spring MVC 애플리케이션 전반에서 시간 데이터를 처리할 때 사용할 기본 시간대를 설정합니다. 주로 서버 측에서 시간대 관련 처리에 영향을 미칩니다.
따라서, **spring.jackson.time-zone**은 JSON 데이터의 직렬화/역직렬화 시 사용되는 Jackson 라이브러리에 적용되고, **spring.mvc.timezone**은 MVC 레이어에서 시간 데이터를 다룰 때 적용됩니다.
 
Share article

keepgoing