주기적으로 데이터 업데이트가 필요한 작업이 있어 스케줄러 컨트롤러를 따로 뽑아내고 작업을 하는 중 문제가 발생했다.
@Component
@EnableScheduling
public class ScheduledApplication {
private static int count = 0;
//실행 1초뒤
@Scheduled(fixedDelay = 1000)
public void testScheduledTask() throws Exception {
System.out.print("스케줄러 실행! "+ count++);
System.out.println(" "+(System.currentTimeMillis()/1000));
}
}
1초마다 실행되어야 할 스케줄러이지만 콘솔창은 다음과 같이 출력되었다.
...
스케줄러 실행! 11 1679364529
스케줄러 실행! 12 1679364529
스케줄러 실행! 13 1679364530
스케줄러 실행! 14 1679364530
스케줄러 실행! 15 1679364531
스케줄러 실행! 16 1679364531
...
스케줄러가 중복으로 작동되는 문제가 발생한 것이였다.
해당 원인은 무엇일까? 찾기 위해 콘솔 메세지를 확인하였다.
...
Spring WebApplicationInitializers detected on classpath
스케줄러 실행! 0 1679364522
Initializing Spring root WebApplicationContext
Initializing Spring FrameworkServlet 'dispatcher'
스케줄러 실행! 1 1679364523
스케줄러 실행! 2 1679364523
...
처음 스케줄러가 실행되는 0은 단 한번만 호출이 되었다.
다만 두번째 WebApplicationContext와 dispatcher 가 작동한 이후,
중복으로 스케줄러가 동일한 시간에 메세지를 출력하는 현상을 발견할 수 있었다.
WebApplicationContext 을 살펴보니 다음과 같은 설정이 되어 있었다.
<context:component-scan base-package="xxx">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
<context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
context:component-scan 에 대해 chatGPT에 물어본 결과 다음과 같이 응답하였다.
context:component-scan 요소와 함께 사용하면
Spring은 지정된 패키지와 하위 패키지에서
@Component 어노테이션이 선언된모든 클래스를 찾아 Bean으로 등록합니다.
이를 통해 개발자는 빈을 수동으로 등록하지 않고도, 자동으로 빈을 등록할 수 있습니다.
필터를 사용하면 빈 등록 시, 추가(include-filter) 및 제외(exclude-filter)가 가능하다.
현재 Controller의 경우 해당 필터에서 제외가 되는 설정으로 되어 있어,
@Coponent 대신 @Controller 를 사용해보았다.
@Controller
@EnableScheduling
public class ScheduledApplication {
private static int count = 0;
//실행 1초뒤
@Scheduled(fixedDelay = 1000)
public void testScheduledTask() throws Exception {
System.out.print("스케줄러 실행! "+ count++);
System.out.println(" "+(System.currentTimeMillis()/1000));
}
}
그 결과는...
...
스케줄러 실행! 3 1679368627
스케줄러 실행! 4 1679368628
스케줄러 실행! 5 1679368629
스케줄러 실행! 6 1679368630
...
된다!
1초 간격으로 스케줄러가 실행되는 모습을 볼 수 있었다.
문제는 WebApplicationContext 가 중복으로 Component를 bean으로 등록하는 것이였다.
이와 같은 문제를 해결하기 위해 필터를 사용하여 exclude 설정을 해주면
context가 Component를 bean으로 등록할 때, 이를 예외처리한다.
사실상 스케줄러의 경우, HTTP 요청을 수행하지 않음으로 컨트롤러로 정의하기에는 애매하다.
따라서 어노테이션은 Component로 수정하고 context에서 추가적으로 exclude-filter를 설정해주었다.
@Component
@EnableScheduling
public class ScheduledApplication {
private static int count = 0;
//실행 1초뒤
@Scheduled(fixedDelay = 1000)
public void testScheduledTask() throws Exception {
System.out.print("스케줄러 실행! "+ count++);
System.out.println(" "+(System.currentTimeMillis()/1000));
}
}
<context:component-scan base-package="xxx">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
<context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:exclude-filter type="assignable" expression="com.test.ScheduledApplication"/>
</context:component-scan>
실행 결과는
스케줄러 실행! 4 1679369285
스케줄러 실행! 5 1679369286
스케줄러 실행! 6 1679369287
스케줄러 실행! 7 1679369288
스케줄러 실행! 8 1679369289
스케줄러 실행! 9 1679369290
마찬가지로 1초마다 작동되는 모습을 볼 수 있다.
* 에러를 겪으면서 처음에는 무작정 인터넷에 검색을 하였는데, 제시하는 설정을 변경하여도 작동이 되지 않았다.
단순히 문제를 해결하려고만 하지 말고, 문제의 원인이 무엇인지 확인을 한 뒤 해결방법을 찾는 것이 더 효과적으로 문제를 해결할 수 있는 것 같다.
'👷삽질기록' 카테고리의 다른 글
로드밸런싱 설정 (1) | 2024.10.17 |
---|---|
java.lang.ClassCastException: oracle.sql.CLOB cannot be cast to java.lang.String (0) | 2023.04.20 |
XSS 취약점 조치 (0) | 2022.11.16 |
There is no getter for property named 'idx' in 'class java.lang.Integer (0) | 2022.09.07 |
java.sql.SQLSyntaxErrorException: ORA-00911: invalid character (0) | 2022.08.31 |
댓글