Here are some files which I used for CronTrigger to solve the issue of
cleanup job starting at the same time on all nodes in cluster. Note that the
cronExpression is coming from the property file which is external to war so
we have different value set for each server. Setting a cron expression for
the past time also gives you a way to disable it completely per server
bases.
-----------
CronTriggerBean.java
-----------

package org.jasig.cas.ticket.registry.support;

import java.util.Date;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.CronExpression;
import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.SchedulerException;
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedOperation;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.quartz.Scheduler;

/**
 * Using the Scheduler and JobDetail, it let's us dynamically change the
cron trigger parameters using jmx.
 *
 * @author mpatel
 * @version 3.3.5
 *
 */
@ManagedResource(objectName = "cas:name=CronTriggerBean", description =
"Cron Trigger")
public class CronTriggerBean {
 /** The Commons Logging instance. */
 private final Log log = LogFactory.getLog(getClass());

private Scheduler scheduler;
 private JobDetail jobDetail;
private String cronExpression;
private CronTrigger cronTrigger;
 private boolean initialized = false;

/**
 * Adds JobDetail to the scheduler once (and only once here) and schedules
the job with the specified cron
 * expression.
 *
 * @throws SchedulerException
 */
public void init() throws SchedulerException {
this.scheduler.addJob(jobDetail, true);
 this.schedule(false);
this.initialized = true;
}

/**
 * Schedules or reschedules the Job with the cron expression using a
CronTrigger.
 * @param reschedule true if reschedule or false for scheduling first time
(through init method)
 */
 private synchronized void schedule(boolean reschedule) {
String triggerName = jobDetail.getFullName() + "_TRIGGER";
 try {
if (reschedule) {
scheduler.unscheduleJob(triggerName, jobDetail.getGroup());
 log.info("Unscheduled " + triggerName + " trigger for the job");
}
 cronTrigger = new CronTrigger(triggerName, jobDetail.getGroup(),
jobDetail.getName(), jobDetail.getGroup());
cronTrigger.setCronExpression(cronExpression);
 cronTrigger.setMisfireInstruction(CronTrigger.MISFIRE_INSTRUCTION_DO_NOTHING);
// Do Nothing on missed fire
Date executionTime = scheduler.scheduleJob(cronTrigger);
 log.info("Job " + jobDetail.getFullName() + " has been scheduled to run at:
" + executionTime
 + " and repeat based on expression: " + cronTrigger.getCronExpression());
} catch (Exception exception) {
 log.error("Error while scheduling the job.", exception);
}
}

/**
 * Checks if the passed string represents a valid cron expression and
reschedules the job accordingly.
 *
 * @param cronExpression String representing a cron expression
 */
 @ManagedAttribute(description = "Set Cron Expression")
public void setCronExpression(String cronExpression) {
 log.debug("Setting cron exression to " + cronExpression);
if (CronExpression.isValidExpression(cronExpression)) {
 this.cronExpression = cronExpression;
if(initialized) {
this.schedule(true);
 }
} else {
log.debug("Invalid cron exression: " + cronExpression);
 }
}

@ManagedAttribute(description = "Get Cron Expression")
 public String getCronExpression() {
return this.cronTrigger.getCronExpression();
 }

@ManagedOperation(description = "Print Trigger Information in HTML format")
 public String printInfoHtml() {
return printInfo("<br/>");
 }

@ManagedOperation(description = "Print Trigger Information")
 public String printInfo() {
return toString();
}

@Override
public String toString() {
return printInfo("\r\n");
 }

private String printInfo(String separator) {
StringBuilder sb = new StringBuilder();
 sb.append("Cron Expression:
").append(this.cronTrigger.getCronExpression()).append(separator);
sb.append("Current Time: ").append(new Date()).append(separator);
 sb.append("Start Time:
").append(this.cronTrigger.getStartTime()).append(separator);
sb.append("Previous Fire Time:
").append(this.cronTrigger.getPreviousFireTime()).append(separator);
 sb.append("End Time:
").append(this.cronTrigger.getEndTime()).append(separator);
sb.append("Next Fire Time: ").append(this.cronTrigger.getFireTimeAfter(new
Date())).append(separator);
 return sb.toString();
}

public void setScheduler(Scheduler scheduler) {
 this.scheduler = scheduler;
}

public void setJobDetail(JobDetail jobDetail) {
 this.jobDetail = jobDetail;
}
}

----------
ticketRegistry.xml
----------
<!--
Value of org.jasig.cas.ticketRegistryCleanerCronExpression should be
different for each server.
 Reason is that, there is no need to fire up this clean-up process on all
servers at the same time as
all of them would try to clean from others and there would be congestion.
 01 - 0 0 0/2 * * ?  - Run every two hours from hour 00 at minute 0 of that
hour.
02 - 0 30 0/2 * * ? - Run every two hours from hour 00 at minute 30 of that
hour.
 03 - 0 0 1/2 * * ?  - Run every two hours from hour 01 at minute 0 of that
hour.
04 - 0 30 1/2 * * ? - Run every two hours from hour 01 at minute 30 of that
hour.
 -->
 <bean id="triggerJobDetailTicketRegistryCleaner"
class="org.jasig.cas.ticket.registry.support.CronTriggerBean"
 p:scheduler-ref="scheduler"
p:jobDetail-ref="jobDetailTicketRegistryCleaner"
 p:cronExpression="${org.jasig.cas.ticketRegistryCleanerCronExpression}"
depends-on="cache"
 init-method="init" />

---------
mbeanContext.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:p="
http://www.springframework.org/schema/p";
 xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd";>
 <description>
MBean related beans goes here.
    </description>

<!--
this bean needs to be eagerly pre-instantiated in order for the
 exporting to occur; this means that it must not be marked as lazily
initialized
 -->
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
 <property name="autodetect" value="true" />
<property name="assembler" ref="assembler" />
 <property name="namingStrategy" ref="namingStrategy" />
</bean>

<!-- (for Java 5+ annotations-based metadata) -->
<bean id="jmxAttributeSource"
 class="org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource"
/>

<bean id="assembler"

class="org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler">
<property name="attributeSource" ref="jmxAttributeSource" />
 </bean>
<!-- will pick up the ObjectName from the annotation -->
 <bean id="namingStrategy"
class="org.springframework.jmx.export.naming.MetadataNamingStrategy">
 <property name="attributeSource" ref="jmxAttributeSource" />
</bean>
 <!-- note that we also have log4jMBean to help us change the logging level
at runtime through MBean and TicketRegistryMBean to search registry by
ticketId in order to debug issues-->
 <!--bean id="log4jMBean" class="xxxcas.util.Log4jMBean"/-->
 <!--bean id="ticketRegistryMBean" class="xxxcas.util.TicketRegistryMBean"
p:jbossCacheTicketRegistry-ref="ticketRegistry"
 /-->
</beans>


On Thu, Apr 22, 2010 at 5:15 PM, Mihir Patel <[email protected]> wrote:

> Yes, so I modified the Job trigger from simple trigger to CronTrigger and
> exposed MBean to change trigger time through jmx-console.
>
>
> On Thu, Apr 22, 2010 at 4:20 PM, Alok Jain <[email protected]> wrote:
>
>>  Hi Mihir,
>>
>>                          Did you get any issues with Both the CAS
>> instances starting the Ticket Cleaning job simultaneously. Did it cause any
>> database issues ?
>>
>>
>>
>> Thanks,
>>
>> Alok.
>>
>>
>>
>> *From:* Mihir Patel [mailto:[email protected]]
>> *Sent:* Tuesday, April 20, 2010 6:25 PM
>>
>> *To:* [email protected]
>> *Subject:* Re: [cas-user] cas HA
>>
>>
>>
>> Hi Alok,
>>
>>
>>
>> When I was working on to upgrade to CAS 3.3.5, I came across the same
>> question you have and I also posted it in forum and at that time Scott B
>> confirmed (
>> http://n4.nabble.com/CAS-Cluster-Is-session-replication-needed-td998800.html)
>>  that
>>  http session clustering is not needed even though it is mentioned in the
>> wiki link below. At my company we have setup of 2 (as well as 4) nodes
>> cluster with JBoss Cache on Tomcat without any clustering at tomcat level
>> (check out my post
>> http://n4.nabble.com/Performance-numbers-with-JBossCache-3-2-1-GA-td1747460.html
>> ).
>>
>>
>>
>> Hope this helps.
>>
>> -Mihir
>>
>> On Tue, Apr 20, 2010 at 5:33 PM, Alok Jain <[email protected]>
>> wrote:
>>
>> Hi Mihir,
>>
>>                                Thanks for your reply .  However the  link
>> http://www.ja-sig.org/wiki/display/CASUM/Clustering+CAS
>>
>> mentions  that clustering *is still required* .
>>
>>
>>
>>
>>
>> Alok.
>>
>>
>>
>>
>>
>>
>>
>> *From:* Mihir Patel [mailto:[email protected]]
>> *Sent:* Tuesday, April 20, 2010 5:21 PM
>> *To:* [email protected]
>> *Subject:* Re: [cas-user] cas HA
>>
>>
>>
>> Hi Alok,
>>
>>
>>
>> Clustering for http sessions at application server level is not required
>> as long as your load balancer has sticky session (session affinity).
>>
>>
>>
>> -Mihir
>>
>> On Tue, Apr 20, 2010 at 5:03 PM, Alok Jain <[email protected]>
>> wrote:
>>
>> Hi ,
>>
>>                  I am using CAS with JPA ticket registry . If I want to
>> have 2 instances of CAS behind the load-balancer , do I still need to do
>> clustering as I am using database for the tickets.
>>
>>
>>
>> Thanks,
>>
>> Alok
>>
>> --
>>
>> You are currently subscribed to [email protected] as: 
>> [email protected]
>>
>>
>>
>>
>>
>>
>>
>>
>> To unsubscribe, change settings or access archives, see 
>> http://www.ja-sig.org/wiki/display/JSG/cas-user
>>
>>
>>
>> --
>>
>> You are currently subscribed to [email protected] as: 
>> [email protected]
>>
>>
>>
>>
>>
>>
>>
>> To unsubscribe, change settings or access archives, see 
>> http://www.ja-sig.org/wiki/display/JSG/cas-user
>>
>>  --
>>
>> You are currently subscribed to [email protected] as: 
>> [email protected]
>>
>>
>>
>> To unsubscribe, change settings or access archives, see 
>> http://www.ja-sig.org/wiki/display/JSG/cas-user
>>
>>
>>
>> --
>>
>> You are currently subscribed to [email protected] as: 
>> [email protected]
>>
>> To unsubscribe, change settings or access archives, see 
>> http://www.ja-sig.org/wiki/display/JSG/cas-user
>>
>>
>

-- 
You are currently subscribed to [email protected] as: 
[email protected]
To unsubscribe, change settings or access archives, see 
http://www.ja-sig.org/wiki/display/JSG/cas-user

Reply via email to