Skip to content
Matt S.Y. Ho edited this page Jul 11, 2016 · 3 revisions

LeaderElection

Choose a implementation of LeaderElection and register it into Spring.

  • CuratorLeaderLatch
  • CuratorLeaderSelector
  • ZooKeeperLeaderElection
<bean id="leaderElection" class="org.shihyu.clustering.scheduler.quorum.CuratorLeaderSelector">
	<property name="connectString" value="localhost:2181"/>
</bean>

Adapt into schedule framework

Spring Scheduling

LeaderElectionTaskScheduler is a TaskScheduler decorator to ensure Runnables runs only if current node elected as leadership.

<bean id="myScheduler" class="org.shihyu.clustering.scheduler.LeaderElectionTaskScheduler">
	<property name="leaderElection" ref="leaderElection"/>
	<property name="taskScheduler">
		<bean class="org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler">
			[...]
		</bean>
	</property>
</bean>
	
<task:annotation-driven scheduler="myScheduler"/>

and your scheduled jobs looks like:

@Slf4j
@Component
public class MyScheduled {

  @Scheduled(fixedRate = 5000)
  public void print() {
    log.info("{}", LocalDateTime.now());
  }
}

Quartz

LeaderElectionSpringBeanJobFactory ensures Jobs runs only if current node elected as leadership as well.

<bean id="myJobFactory" class="org.shihyu.clustering.scheduler.quartz.LeaderElectionJobFactory">
	<property name="jobFactory">
		<bean class="org.springframework.scheduling.quartz.SpringBeanJobFactory"></bean>
	</property>
	<property name="leaderElection" ref="leaderElection"/>
</bean>

<bean id="quartzScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
	<property name="jobFactory" ref="myJobFactory"/>
	<property name="schedulerName" value="MyScheduler" />
	<property name="triggers">
		<list>
		    <ref bean="myTrigger" />
		</list>
	</property>
</bean>

<bean id="myTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
    <property name="jobDetail" ref="myJobDetail"/>
    <property name="cronExpression" value="0/5 * * * * ?" />
</bean> 
<bean id="myJobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
    <property name="jobClass" value="org.shihyu.clustering.scheduler.MyJob"/>
</bean>

and this is your job:

@Slf4j
public class MyJob implements Job {

  @Override
  public void execute(JobExecutionContext context) throws JobExecutionException {
    log.info("{}", LocalDateTime.now());
  }
}

Control scheduled jobs

org.shihyu.clustering.scheduler.ScheduleManager provides API to control:

@RestController
@RequestMapping("/jobs")
public class JobController {

  @Autowired
  private ScheduleManager manager;

  @RequestMapping("/pause")
  public void pause() {
    manager.pause();
  }

  @RequestMapping("/resume")
  public void resume() {
    manager.resume();
  }

  @RequestMapping("/relinquish")
  public void relinquish() {
    manager.relinquishLeadership();
  }

  @RequestMapping("/is-leader")
  public boolean isLeader() {
    return manager.isLeader();
  }
  
  @RequestMapping("/participants")
  public Map<String, Boolean> getParticipants() {
    return manager.getParticipants();
  }

}

If you use Spring Scheduling and Quartz at the same time, you can register org.shihyu.clustering.scheduler.ScheduleManagers, and make it primary to take over control.

<bean id="scheduleManager" 
	class="org.shihyu.clustering.scheduler.ScheduleManagers" 
	primary="true"></bean>
Clone this wiki locally