Quartz를 이용해 Job을 스케쥴링할 때 Job의 수행시간이 스케쥴러의 주기 보다 길어지면 Job이 중복 실행되면서 문제가 발생할 수 있다.
예를들어 내부 시스템으로 접수된 적하목록에 대해 검사선별을 위해 선별배치가 수행되는데, 언제 접수될 지 모르는 적하목록을 폴링해야 하므로 데몬 배치로 개발되었으나, 스프링배치를 적용 하면서 1분을 주기로 스케쥴링을 하게된다. 이때 처음 실행된 Job이 적하목록 선별 건수가 많아 1분을 경과하여 실행될 때 새로운 스케쥴러에 의해 Job이 중복 수행되면 선별처리에 문제가 생기게 된다.
Job을 구현한 클래스에 @DisallowConcurrentExecution 어노테이션을 적용하면 동시성 방지 처리가 된다.
→ 매 1분마다 Job 실행
→ sleep 타임 이후 Job 실행
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!-- Service Class -->
<bean id="selectivityJobService" class="py.gov.rms.sm.batch.selectivity.service.SelectivityJobService" />
<bean name="selectivityJob" class="org.springframework.scheduling.quartz.JobDetailFactoryBean"><!-- Quartz 2.x 버전 -->
<property name="jobClass">
<value>py.gov.rms.sm.batch.selectivity.scheduler.SelectivityJobMain</value>
</property>
<!--jobClass에 넘길 데이터에 위에 선언한 Service 세팅 -->
<property name="jobDataAsMap">
<map>
<entry key="selectivityJobService" value-ref="selectivityJobService"/>
</map>
</property>
</bean>
<bean id="selectivityTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"><!-- Quartz 2.x 버전 -->
<property name="jobDetail">
<ref bean="selectivityJob"/>
</property>
<property name="cronExpression">
<value>0 0/1 * * * ?</value>
</property>
</bean>
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="selectivityTrigger"/>
</list>
</property>
</bean>
</beans>
package py.gov.rms.sm.batch.selectivity.scheduler;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.quartz.QuartzJobBean;
import py.gov.rms.sm.batch.selectivity.service.SelectivityJobService;
// 동시성 방지 처리
@DisallowConcurrentExecution
public class SelectivityJobMain extends QuartzJobBean {
private final Logger logger = LoggerFactory.getLogger( SelectivityJobMain.class );
/** Service를 사용하기위해서는 "context-quartz.xml"에 <bean>으로 등록후
* FactoryBean의 "jobDataAsMap" 설정을 해줘야함
*/
private SelectivityJobService selectivityJobService;
public void setSelectivityJobService( SelectivityJobService selectivityJobService) {
this.selectivityJobService = selectivityJobService;
}
@Override
public void executeInternal( JobExecutionContext context ) throws JobExecutionException {
logger.debug( "Selectivity Job executeInternal" );
try {
selectivityJobService.preManifestSelectivity();
} catch (Exception e) {
e.printStackTrace();
}
}
}
package py.gov.rms.sm.batch.selectivity.service;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import py.gov.rms.common.util.CommonUtil;
@Service( "selectivityJobService" )
public class SelectivityJobService {
private final Logger logger = LoggerFactory.getLogger( SelectivityJobService.class );
public void preManifestSelectivity() throws Exception {
logger.debug(">>>> preManifestSelectivity...");
try {
Thread.sleep(1000 * 80); //1분 20초 대기
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("sleep 실행 후");
}
public static void main(String[] args) {
// TODO Auto-generated method stub
}
}