반응형

보통 스케줄러를 구성할때 크론탭으로 일정시간을 하드코딩으로 넣거나 프로퍼티 또는 db에서 가져와서 세팅하는 형태로 많이 구현을 하는데, 요구사항으로 입력에 따라 운용중인 시스템에서 스케줄러 동작 시간이 변경되도록 구현이 되어야 했다.

 

자바8 이상 기준으로 작성되었습니다.

 

ThreadPoolTaskScheduler 클래스를 통해 구현을 진행했다.

동적 스케줄러 구성하기

DynamicChangeScheduler.java

import java.time.LocalDateTime;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;

@Component
public class DynamicChangeScheduler {
	private ThreadPoolTaskScheduler scheduler;
	private String cron = "*/2 * * * * *";

	public void startScheduler() {
		scheduler = new ThreadPoolTaskScheduler();
		scheduler.initialize();
		// scheduler setting 
		scheduler.schedule(getRunnable(), getTrigger());
	}

	public void changeCronSet(String cron) {
		this.cron = cron;
	}

	public void stopScheduler() {
		scheduler.shutdown();
	}

	private Runnable getRunnable() {
		// do something
		return () -> {
			System.out.println(LocalDateTime.now().toString());
		};
	}

	private Trigger getTrigger() {
		// cronSetting
		return new CronTrigger(cron);
	}

	@PostConstruct
	public void init() {
		startScheduler();
	}

	@PreDestroy
	public void destroy() {
		stopScheduler();
	}
}

일반적으로 @Scheduled 어노테이션으로 크론탭이나 주기시간을 입력하여 동작하도록 처리하는데, ThreadPoolTaskScheduler를 통해 스케줄러를 생성하고 run을 시키는 형태로 구현하였다.

프로젝트가 구동하자마자 동작을 시키기 위해 postContruct 어노테이션 메소드에 startScheduler메소드 실행하여 스케줄러가 바로 동작하도록 하였다.

 

getRunnable 메소드에 정의된 실행 동작으로 인해 처음엔 2초마다 현재 시간을 찍어대기 시작한다.

 

view페이지에서 입력이 들어오면 시간을 바꾸도록 하였다.

AdminController.java

import java.util.HashMap;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import egovframework.srok.sheduler.DynamicChangeScheduler;

@Controller
public class AdminController {
	
	@Autowired
	DynamicChangeScheduler ps;
	
	@RequestMapping(value="/setting.do")
	public ModelAndView setting() throws Exception{
		ModelAndView mv = new ModelAndView();
		mv.setViewName("admin/setting");
		return mv;
	}
	
	@RequestMapping(value="/updateScheduler.do")
	public @ResponseBody HashMap<Object, Object> updateScheduler(@RequestParam  HashMap<Object, Object> params) throws Exception{
		ps.stopScheduler();
		Thread.sleep(1000);
		ps.changeCronSet((String) params.get("cron"));
		ps.startScheduler();
		
		HashMap<Object, Object> res = new HashMap<Object, Object>();
		res.put("res", "success");
		return res;
	}
	
	@RequestMapping(value="/pauseScheduler.do")
	public @ResponseBody HashMap<Object, Object> pauseScheduler(@RequestParam  HashMap<Object, Object> params) throws Exception{
		ps.stopScheduler();
		HashMap<Object, Object> res = new HashMap<Object, Object>();
		res.put("res", "success");
		return res;
	}
}

 

admin/setting.jsp

<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>스케줄러 테스트</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
</head>
<body>
    <h1>스케줄러 동작 시간 변경 테스트</h1>
    <input type="text" id="cronTab">
    <br/>
    <a href="javascript:void(0);" id="changeTest">스케줄러 동작 시간 변경</a>
    <a href="javascript:void(0);" id="pauseTest">스케줄러 중지</a>
</body>
<script>
$(function(){
    $(document).on("click", "#changeTest", function(){
		$.ajax({
	        url: 'updateScheduler.do',
	        type: 'POST',
	        data: {cron: $("#cronTab").val()},
	        success: function (data) {
	    		if(data.res == "success"){
	    		    alert("스케줄러 동작 시간이 변경되었습니다.");
	    		    location.reload();
	    		}
	        },
	        error: function (error) {
	    		console.log(error)
	        }
	    });
    }).on("click", "#pauseTest", function(){
		$.ajax({
	        url: 'pauseScheduler.do',
	        type: 'POST',
	        data: '',
	        success: function (data) {
	    		if(data.res == "success"){
	    		    alert("스케줄러가 멈췄습니다.");
	    		    location.reload();
	    		}
	        },
	        error: function (error) {
	    		console.log(error)
	        }
	    });
	
    });
});
</script>
</html>

input 박스에 크론탭형태로 데이터를 넣고 시간 변경을 하면 변경된 크론 형태로 스케줄러가 동작하고, 중지를 누르면 기존에 동작하던 스케줄러가 멈추도록 구성하였다.

반응형