배치 Job Sample Project

  1. 기본 설명

    이 예제는 Glue Job Scheduler 를 이용하지 않고 배치 Job 을 테스트하는 예제이다.

  2. 사용법
    • 이클립스에 다운로드 받은 sample-schedule 프로젝트를 import 한다.

      (import - General - Existing Projects into Workspace)

    • applicationContext.xml 파일을 열어 datasource 부분을 로컬환경에 맞춰 수정한다.
      <!-- sqlite 의 경우 -->
      <bean id="test-dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
          <property name="driverClassName" value="org.sqlite.JDBC"/>
          <property name="url" value="jdbc:sqlite:/C://apache-tomcat-7.0.79/sample.db"/>  
          <property name="defaultAutoCommit" value="false"/>
          <property name="minIdle" value="0"/>
          <property name="maxActive" value="1"/>
          <property name="maxIdle" value="1000"/>
      </bean>
      <!-- oracle 일 경우
      <bean id="securityDs" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
          <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
          <property name="url" value="jdbc:oracle:thin:@데이타베이스주소:1521:XE"/>
          <property name="username" value="아이디"/>
          <property name="password" value="비번"/>
          <property name="defaultAutoCommit" value="false"/>
          <property name="minIdle" value="0"/>
          <property name="maxActive" value="-1"/>
          <property name="maxIdle" value="1000"/>
      </bean>
      -->
      
    • Quartz 를 이용할 경우, quartz-scheduler.xml 를 활용.

      quartz-scheduler.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"
          xsi:schemaLocation="http://www.springframework.org/schema/beans
                              http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
          <bean id="scheduler" 
                class="org.springframework.scheduling.quartz.SchedulerFactoryBean" >
              <property name="triggers">
                  <list>
                      <ref local="simpleTrigger1"/>
                      <ref local="simpleTrigger2"/>
                      <ref local="cronTrigger"/>
                  </list>
              </property>
          </bean>
      
          <bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
              <property name="jobDetail" ref="jobDetail-A"/>
              <property name="cronExpression" value="0 40 15 * * ?"/>
          </bean>
          <bean id="simpleTrigger1" 
                class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
              <property name="jobDetail" ref="jobDetail-B"/>
              <property name="repeatInterval" value="10000"/> 
              <property name="repeatCount" value="3"/>
              <property name="startDelay" value="5000"/>
          </bean>
          <bean id="simpleTrigger2" 
                class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
              <property name="jobDetail" ref="jobDetail-C"/>
              <property name="repeatInterval" value="7000"/>
          </bean>
      
          <bean id="jobDetail-A" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
              <property name="jobClass" 
                        value="com.poscoict.glueframework.scheduling.GlueQuartzJobBean"/>
              <property name="jobDataAsMap">
                  <map>
                      <entry key="ServiceName" value="hello-service"/>                
                      <entry key="input" value="Glue"/>
                  </map>
              </property>
          </bean>
          <bean id="jobDetail-B" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
              <property name="jobClass" 
                        value="com.poscoict.glueframework.scheduling.GlueQuartzJobBean"/>
              <property name="jobDataAsMap">
                  <map>
                      <entry key="ServiceName" value="dept-service"/>
                      <entry key="DEPTNO" value="60"/>
                      <entry key="DNAME" value="Testing"/>
                      <entry key="LOC" value="seoul"/>
                      <entry key="insert" value="event"/>
                  </map>
              </property>
          </bean>
          <bean id="jobDetail-C" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
              <property name="jobClass" 
                        value="com.poscoict.glueframework.scheduling.GlueQuartzJobBean"/>
              <property name="jobDataAsMap">
                  <map>
                      <entry key="ServiceName" value="dept-service"/>
                      <entry key="DEPTNO" value="60"/>
                      <entry key="delete" value="event"/>
                  </map>
              </property>
          </bean>
      </beans>
      
    • Spring Scheduler 를 이용할 경우, spring-scheduler.xml 를 활용.

      spring-scheduler.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/beans
                              http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                              http://www.springframework.org/schema/task
                              http://www.springframework.org/schema/task/spring-task.xsd">
      
          <task:scheduled-tasks scheduler="scheduler">
              <task:scheduled ref="glue-task-1" method="doGlueService" 
                                                cron="0/8 * * * * MON-FRI"/> 
              <task:scheduled ref="glue-task-2" method="doGlueService" fixed-rate="70000"/> 
              <task:scheduled ref="glue-task-3" method="doGlueService" fixed-delay="50000"/>
          </task:scheduled-tasks>
      
          <task:scheduler id="scheduler" pool-size="3" />
      
          <bean id="glue-task-1" 
                class="com.poscoict.glueframework.scheduling.task.GlueTaskScheduler">
              <property name="ServiceName" value="hello-service"/>
              <property name="dataMap">
                  <map>
                      <entry key="input" value="Glue"/>
                  </map>
              </property>
          </bean>
          <bean id="glue-task-2" 
                class="com.poscoict.glueframework.scheduling.task.GlueTaskScheduler">
              <property name="ServiceName" value="dept-service"/>
              <property name="dataMap">
                  <map>
                      <entry key="DEPTNO" value="50"/>
                      <entry key="DNAME" value="Marketing"/>
                      <entry key="LOC" value="SEOUL"/>
                      <entry key="insert" value="event"/>
                  </map>
              </property>
          </bean>
          <bean id="glue-task-3" 
                class="com.poscoict.glueframework.scheduling.task.GlueTaskScheduler">
              <property name="ServiceName" value="dept-service"/>
              <property name="dataMap">
                  <map>
                      <entry key="DEPTNO" value="50"/>
                      <entry key="delete" value="event"/>
                  </map>
              </property>
          </bean>
      </beans>
      
    • 외부 라이브러리가 추가 될 경우, build.xml 수정

      Oracle 을 이용할 경우, GlueSDK/lib 아래 gluestd_oracle 폴더 생성하고 라이브러리 위치시킴.

      <?xml version="1.0"?>
      <project name="GlueSchedulerSample" default="jar1">
          <!-- default 값을 패키징 유형에 따라 변경해서 ant build 실행 -->    
          <property file="build.properties"/>
          <target name="init" description="clean build directory before packaging">
              <delete failonerror="false">
                  <fileset dir="${build.dir}">
                      <include name="*.*"/>
                  </fileset>          
              </delete>
              <mkdir dir="${build.dir}"/>
              <mkdir dir="${build.dir}/lib"/>
          </target>
          <!-- Main-Class 생성, include schedule library path info
               jar1 : Main-Class 포함하며 quartz-scheduler.xml, spring-scheduler.xml 포함하는 jar packaging -->
          <path id="class.path1">        
              <fileset dir="${GlueSDK.dir}/lib/gluelib">
                  <include name="glue-core-*.jar"/>
                  <include name="glue-schema-*.jar"/>
                  <include name="glue-schedule-*.jar"/>
                  <include name="license-*.jar"/>
              </fileset>
              <fileset dir="${GlueSDK.dir}/lib/gluestd">
                  <include name="aopalliance*.jar"/>
                  <include name="bcprov*.jar"/>
                  <include name="xmlbeans*.jar"/>
                  <include name="jaxp-api*.jar"/>
                  <include name="spring*.jar"/>
                  <include name="ehcache*.jar"/>
                  <include name="slf4j*.jar"/>
                  <include name="logback*.jar"/>
                  <include name="jcl*.jar"/>
                  <include name="commons*.jar"/>
                  <include name="sqlite*.jar"/>
              </fileset>
              <fileset dir="${GlueSDK.dir}/lib/gluestd_schedule"><include name="*.jar"/></fileset>        
          </path>
          <pathconvert property="class-path1" pathsep=" " dirsep="\">
              <path refid="class.path1"></path>
              <map from="${GlueSDK.dir}/lib/gluelib" to="lib"/>
              <map from="${GlueSDK.dir}/lib/gluestd_schedule" to="lib"/>              
              <map from="${GlueSDK.dir}/lib/gluestd" to="lib"/>
          </pathconvert>
          <target name="jar1" depends="init" description="Creates the JAR file">
              <jar destfile="${build.dir}/${JAR1_NAME}.jar">
                  <manifest>
                      <section name="POSCO ICT Glue Sample Project">
                          <attribute name="Implementation-Version" value="${project_version}"/>
                      </section>
                      <attribute name="Main-Class" value="com.poscoict.glueframework.scheduling.server.GlueSchedulerHttpServer"/>
                      <attribute name="Class-Path" value="${class-path1}" />
                  </manifest>
                  <fileset dir="${class.dir}">
                      <patternset>
                          <include name="**/*.*"/>
                      </patternset>
                  </fileset>
              </jar>
              <!-- 로컬에서 테스트시에는 사용하고, 개발계등에서는 직접 라이브러리 복사 -->
              <copy todir="${build.dir}/lib">            
                  <fileset dir="${GlueSDK.dir}/lib/gluelib">
                      <include name="glue-core-*.jar"/>
                      <include name="glue-schema-*.jar"/>
                      <include name="glue-schedule-*.jar"/>
                      <include name="license-*.jar"/>
                  </fileset>
                  <fileset dir="${GlueSDK.dir}/lib/gluestd">
                      <include name="aopalliance*.jar"/>
                      <include name="bcprov*.jar"/>
                      <include name="xmlbeans*.jar"/>
                      <include name="jaxp-api*.jar"/>
                      <include name="spring*.jar"/>
                      <include name="ehcache*.jar"/>
                      <include name="slf4j*.jar"/>
                      <include name="logback*.jar"/>
                      <include name="jcl*.jar"/>
                      <include name="commons*.jar"/>
                      <include name="sqlite*.jar"/>
                  </fileset>
                  <fileset dir="${GlueSDK.dir}/lib/gluestd_schedule"><include name="*.jar"/></fileset>            
              </copy>
          </target>
          
          <!-- jar2 : user job packaging for using scheduler-server, 실행유형이 class 일 경우
          해당 jar 를 배치시키는 scheduler-server/apps/lib 아래에 class path 에 해당하는 library 들을 복사해야 함
          참고로 glue-scheduler-job-x.x.x.jar
          -->
          <path id="class.path2">        
              <fileset dir="${GlueSDK.dir}/lib/gluelib">
                  <include name="glue-core-*.jar"/>
                  <include name="glue-schema-*.jar"/>
                  <include name="glue-schedule-*.jar"/>
                  <include name="license-*.jar"/>
              </fileset>
              <fileset dir="${GlueSDK.dir}/lib/gluestd">
                  <include name="aopalliance*.jar"/>
                  <include name="bcprov*.jar"/>
                  <include name="xmlbeans*.jar"/>
                  <include name="jaxp-api*.jar"/>
                  <include name="spring*.jar"/>
                  <include name="ehcache*.jar"/>
                  <include name="slf4j*.jar"/>
                  <include name="logback*.jar"/>
                  <include name="jcl*.jar"/>
                  <include name="commons*.jar"/>
                  <include name="sqlite*.jar"/>
              </fileset>              
          </path>
          <pathconvert property="class-path2" pathsep=" " dirsep="\">
              <path refid="class.path2"></path>
              <map from="${GlueSDK.dir}/lib/gluelib" to="lib"/>                       
              <map from="${GlueSDK.dir}/lib/gluestd" to="lib"/>
          </pathconvert>
          <target name="jar2" depends="init" description="Creates the JAR file for scheduler-server">
              <jar destfile="${build.dir}/${JAR2_NAME}.jar">          
                  <fileset dir="${class.dir}">
                      <patternset>
                          <include name="**/*.*"/>
                          <exclude name="spring-scheduler.xml"/>
                          <exclude name="quartz-scheduler.xml"/>
                      </patternset>
                  </fileset>
              </jar>
          </target>
          
          <!-- jar3 : user job packaging for using scheduler-server, 실행유형이 jarfile 일 경우
          해당 jar 를 배치시키는 scheduler-server/apps/lib 아래에 class path 에 해당하는 library 들을 복사해야 함
          glue-scheduler-job-x.x.x.jar 도 class path 에 포함되게 ${GlueSDK.dir}/lib/gluestd_schedule 위치에 미리 복사해 둬야 함  
          -->
          <target name="jar3" depends="init" description="Creates the JAR file for scheduler-server">
              <jar destfile="${build.dir}/${JAR3_NAME}.jar">
                  <manifest>
                      <section name="POSCO ICT Glue Sample Project">
                          <attribute name="Implementation-Version" value="${project_version}"/>
                      </section>
                      <attribute name="Main-Class" value="com.poscoict.app.job.GlueSimpleJob"/>
                      <attribute name="Class-Path" value="${class-path1}" />
                  </manifest>
                  <fileset dir="${class.dir}">
                      <patternset>
                          <include name="**/*.*"/>
                          <exclude name="spring-scheduler.xml"/>
                          <exclude name="quartz-scheduler.xml"/>
                      </patternset>
                  </fileset>
              </jar>
          </target>
      </project>           
      
    • ant build 를 이용해 build 를 수행하면, 프로젝트내에 build 디렉토리 아래에 user-application.jar 가 생성된다.
    • Windows 의 경우 cmd 를 실행한 후, 해당 build 디렉토리로 이동.
    • Quartz 를 이용 할 경우,

      java -jar user-application.jar quartz quartz-scheduler.xml 로 실행.

    • Spring Scheduler 를 이용 할 경우,

      java -jar user-application.jar spring spring-scheduler.xml 로 실행.

    • 실행종료는 Ctrl+C 를 입력한다.
    • project attribute init 에 jar1, jar2, jar3 입력 후 build 수행 가능
    • jar1 은 배치성 job 을 quartz or spring 관련 xml 설정을 이용해 수행시
      jar2, jar3 은 scheduler-manager 를 통해 metadata 를 등록해 수행시 이용되는데
      jar2 의 경우는 실행유형이 class, jar3 의 경우는 실행유형이 jarfile 일 경우 이용