Showing posts with label quartz. Show all posts
Showing posts with label quartz. Show all posts

Thursday, April 7, 2016

Quartz with Spring - Java configuration

In my previous post Quartz with Spring and embedded database I have used xml to configure spring 3 with quartz 1.8.

Now I will configure spring 4.2 with quartz 2.2.2 using Java configuration. I am using quartz in cluster.

Java configuration class

@Configuration
@ComponentScan({ "hr.samara.job" })
public class QuartzConfig
{

@Autowired
private DataSource dataSource;
@Autowired
private JpaTransactionManager transactionManager;
@Autowired
private Environment env;

@Autowired
private SimOperation simOperation;

@Bean
public SchedulerFactoryBean scheduler()
{
SchedulerFactoryBean scheduler = new SchedulerFactoryBean();
scheduler.setConfigLocation(new ClassPathResource("quartz.properties"));

scheduler.setDataSource(dataSource);
scheduler.setTransactionManager(transactionManager);

// inject simOperation - spring bean in job
Map<String, Object> map = new HashMap<>();
map.put("simOperation", simOperation);
scheduler.setSchedulerContextAsMap(map);


scheduler.setTriggers(blockSimTrigger().getObject());
return scheduler;
}

@Bean
public CronTriggerFactoryBean blockSimTrigger()
{
CronTriggerFactoryBean cronTriggerFactoryBean = new CronTriggerFactoryBean();
cronTriggerFactoryBean.setJobDetail(blockSimJob().getObject());
cronTriggerFactoryBean.setCronExpression(env.getProperty("job.blockSim.cron"));
cronTriggerFactoryBean.setMisfireInstructionName("MISFIRE_INSTRUCTION_FIRE_ONCE_NOW");
return cronTriggerFactoryBean;
}

@Bean
public JobDetailFactoryBean blockSimJob()
{
JobDetailFactoryBean jobDetailFactory = new JobDetailFactoryBean();
jobDetailFactory.setJobClass(BlockSimJob.class);
jobDetailFactory.setDescription("call sim block");
return jobDetailFactory;
}

}


Job class

@DisallowConcurrentExecution
public class BlockSimJob extends QuartzJobBean
{

private transient SimOperation simOperation;

@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException
{
simOperation.blockSim();
}

public void setSimOperation(SimOperation simOperation)
{
this.simOperation = simOperation;
}

}


Ref:
http://www.baeldung.com/spring-quartz-schedule

Wednesday, July 29, 2015

Quartz troubleshooting

Problem:
Quartz in clustered mode, nodes are sync via db.
There are many lines like these in logs:
[2015-07-04 00:00:01,620]  WARN [QuartzScheduler_scheduler-prov011435933239135_ClusterManager] (JobStoreSupport.java:3298) - This scheduler instance (prov011435933239135) is still active but was recovered by another instance in the cluster.  This may cause inconsistent behavior.

"The most probable cause of such a cluster-related error is having cluster nodes with system clock not synchronized."



Ref:
http://quartz-scheduler.org/documentation/faq

Friday, July 17, 2015

Quartz with Spring and embedded database

I'm was testing quartz at localhost with H2 embedded database.
In this case I need quartz tables prepared.

In spring config define database and wha script to load:
<jdbc:embedded-database id="dataSource" type="H2">
<jdbc:script location="classpath:recycle/quartz-h2.sql" />
</jdbc:embedded-database>


Example of spring 3.2 integration with quart 1.8:

<?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.xsd
                             http://www.springframework.org/schema/task
                             http://www.springframework.org/schema/task/spring-task.xsd">
                           
<!-- Setting pool to 10 threads -->
    <task:scheduler id="taskScheduler" pool-size="10"/>

    <!-- Scheduler -->
    <bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="configLocation" value="recycle/quartz.properties"/>
        <property name="dataSource" ref="dataSource"/>
        <property name="transactionManager" ref="transactionManager" />
        <property name="triggers">
        <list>
                <ref bean="txRecycleTrigger" />
            </list>
        </property>
        <!-- Fill the schedulerFactoryBeans scheduleContextMap with ALL spring
beans that shall be available for the Job implementations. The SpringBeanJobFactory will inject these beans into newly instantiated workers if they have a setter that corresponds to the beans key. This makes spring beans available even for (persisted and) deserialized Jobs. NOTE: This mechanism isn't supported by Spring 3.0 for the latest Quartz version 2.0.1 but for the previous version 1.8.5 -->
<property name="schedulerContextAsMap">
<map>
<entry key="recycleSimService" value-ref="RecycleSimService" />
<entry key="logEnabled" value="${job.logEnabled}" />
</map>
</property>
    </bean>
 
    <!-- Property ""MISFIRE_INSTRUCTION_FIRE_ONCE_NOW" means that The job is executed immediately after the scheduler discovers misfire situation.  -->
 
    <bean id="txRecycleTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <property name="jobDetail"      ref  ="recycleSimJob" />
        <property name="cronExpression" value="${job.recycleScheduler.cronExpression}" />
        <property name="misfireInstructionName" value="MISFIRE_INSTRUCTION_FIRE_ONCE_NOW" />
    </bean>
    <bean id="recycleSimJob" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
      <property name="jobClass" value="com.samara.job.RecycleSimJob" />
    </bean>
 
</beans>



Job implementation

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.StatefulJob;
import org.springframework.scheduling.quartz.QuartzJobBean;

public class RecycleSimJob extends QuartzJobBean implements StatefulJob
{
 private transient static final Logger log = LoggerFactory.getLogger(RecycleSimJob.class);

 private transient RecycleSimService recycleSimService;

 @Override
 protected void executeInternal(JobExecutionContext context) throws JobExecutionException
 {
  if (getRecycleSimService() == null)
  {
   log.warn("recycleSimService is not set!");
   return;
  }
  getRecycleSimService().recycleSims(new Date());
 }

 public RecycleSimService getRecycleSimService()
 {
  return recycleSimService;
 }

 public void setRecycleSimService(RecycleSimService recycleSimService)
 {
  this.recycleSimService = recycleSimService;
 }

}

Schedule job in real time

I'm using injected org.springframework.scheduling.quartz.SchedulerFactoryBean.

JobDetail jobDetail = new JobDetail("deactivation_" + orderId, DeactivateOrderJob.class);
Map<String, Long> params = new HashMap<String, Long>();
params.put("orderId", orderId);
jobDetail.setJobDataMap(new JobDataMap(params));
final SimpleTrigger simpleTrigger = new SimpleTrigger("deactivationTrigger_" + orderId, expiryTime);
schedulerFactory.getScheduler().scheduleJob(jobDetail, simpleTrigger);

DeactivateOrderJob will be waken and it will read orderId from map.

@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException
{
     Map params = context.getJobDetail().getJobDataMap();
     Long orderId = (Long) params.get("orderId");
     .....
}