Let's say I have a trigger configured this way:
<bean id="updateInsBBTrigger"
class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="updateInsBBJobDetail"/>
<!-- run every morning at 5 AM -->
<property name="cronExpression" value="0 0 5 * * ?"/>
</bean>
The trigger have to connect with another application and if there is any problem (like a connection failure) it should to retry the task up to five times every 10 minutes or until success. There is any way to configure the trigger to work like this?
I would recommend an implementation like this one to recover the job after a fail:
final JobDataMap jobDataMap = jobCtx.getJobDetail().getJobDataMap();
// the keys doesn't exist on first retry
final int retries = jobDataMap.containsKey(COUNT_MAP_KEY) ? jobDataMap.getIntValue(COUNT_MAP_KEY) : 0;
// to stop after awhile
if (retries < MAX_RETRIES) {
log.warn("Retry job " + jobCtx.getJobDetail());
// increment the number of retries
jobDataMap.put(COUNT_MAP_KEY, retries + 1);
final JobDetail job = jobCtx
.getJobDetail()
.getJobBuilder()
// to track the number of retries
.withIdentity(jobCtx.getJobDetail().getKey().getName() + " - " + retries, "FailingJobsGroup")
.usingJobData(jobDataMap)
.build();
final OperableTrigger trigger = (OperableTrigger) TriggerBuilder
.newTrigger()
.forJob(job)
// trying to reduce back pressure, you can use another algorithm
.startAt(new Date(jobCtx.getFireTime().getTime() + (retries*100)))
.build();
try {
// schedule another job to avoid blocking threads
jobCtx.getScheduler().scheduleJob(job, trigger);
} catch (SchedulerException e) {
log.error("Error creating job");
throw new JobExecutionException(e);
}
}
Why?
It will not block Quartz Workers
It will avoid back pressure. With setRefireImmediately the job will be fired immediately and it could lead to back pressure issues
Source: Automatically Retry Failed Jobs in Quartz
If you want to have a job which keeps trying over and over again until it succeeds, all you have to do is throw a JobExecutionException with a flag to tell the scheduler to fire it again when it fails. The following code shows how:
class MyJob implements Job {
public MyJob() {
}
public void execute(JobExecutionContext context) throws JobExecutionException {
try{
//connect to other application etc
}
catch(Exception e){
Thread.sleep(600000); //sleep for 10 mins
JobExecutionException e2 = new JobExecutionException(e);
//fire it again
e2.setRefireImmediately(true);
throw e2;
}
}
}
It gets a bit more complicated if you want to retry a certain number of times. You have to use a StatefulJob and hold a retryCounter in its JobDataMap, which you increment if the job fails. If the counter exceeds the maximum number of retries, then you can disable the job if you wish.
class MyJob implements StatefulJob {
public MyJob() {
}
public void execute(JobExecutionContext context) throws JobExecutionException {
JobDataMap dataMap = context.getJobDetail().getJobDataMap();
int count = dataMap.getIntValue("count");
// allow 5 retries
if(count >= 5){
JobExecutionException e = new JobExecutionException("Retries exceeded");
//make sure it doesn't run again
e.setUnscheduleAllTriggers(true);
throw e;
}
try{
//connect to other application etc
//reset counter back to 0
dataMap.putAsString("count", 0);
}
catch(Exception e){
count++;
dataMap.putAsString("count", count);
JobExecutionException e2 = new JobExecutionException(e);
Thread.sleep(600000); //sleep for 10 mins
//fire it again
e2.setRefireImmediately(true);
throw e2;
}
}
}
I would suggest for more flexibility and configurability to better store in your DB two offsets: the repeatOffset which will tell you
after how long the job should be retried and the trialPeriodOffset which will keep the information of the time window that the job is
allowed to be rescheduled. Then you can retrieve these two parameters like (I assume you are using Spring):
String repeatOffset = yourDBUtilsDao.getConfigParameter(..);
String trialPeriodOffset = yourDBUtilsDao.getConfigParameter(..);
Then instead of the job to remember the counter it will need to remember the initalAttempt:
Long initialAttempt = null;
initialAttempt = (Long) existingJobDetail.getJobDataMap().get("firstAttempt");
and perform the something like the following check:
long allowedThreshold = initialAttempt + Long.parseLong(trialPeriodOffset);
if (System.currentTimeMillis() > allowedThreshold) {
//We've tried enough, time to give up
log.warn("The job is not going to be rescheduled since it has reached its trial period threshold");
sched.deleteJob(jobName, jobGroup);
return YourResultEnumHere.HAS_REACHED_THE_RESCHEDULING_LIMIT;
}
It would be a good idea to create an enum for the result of the attempt that is being returned back to the core workflow of your
application like above.
Then construct the rescheduling time:
Date startTime = null;
startTime = new Date(System.currentTimeMillis() + Long.parseLong(repeatOffset));
String triggerName = "Trigger_" + jobName;
String triggerGroup = "Trigger_" + jobGroup;
Trigger retrievedTrigger = sched.getTrigger(triggerName, triggerGroup);
if (!(retrievedTrigger instanceof SimpleTrigger)) {
log.error("While rescheduling the Quartz Job retrieved was not of SimpleTrigger type as expected");
return YourResultEnumHere.ERROR;
}
((SimpleTrigger) retrievedTrigger).setStartTime(startTime);
sched.rescheduleJob(triggerName, triggerGroup, retrievedTrigger);
return YourResultEnumHere.RESCHEDULED;
Related
I am trying to create a Spring boot application, which asynchronously process thousand of records using #Async multithreading. For this I am creating 8 threads and 8 sub list from main list so that 8 thread process 8 sub list asynchronously. I am also using #scheduler so that method calls in every 2 seconds.
But problem is that due to scheduler, sometimes this application process duplicate records because this method get called in every 2 seconds and retrieve data from database in every 2 seconds. for example first time method get called and retrieved 72000 records from database whose flag 0 and then #Async method process all these records and change processed records flag from 0 to 1. And again in 2 seconds method get called and retrieve new records wh0se flag is 0.
In log attached pic you can see that first time scheduler get called and retrieved 72000 records and multiple threads started processing in between next scheduler started and retrieved 16000 records which contain those records also which are present in current scheduler.
I am looking solution that next scheduler should not call until first scheduler get completed. Because sometime first scheduler processing records in between if next scheduler call in 2 seconds then may be it retrieve those records again which are already present in first scheduler call.
I can't increase scheduler call time. Because maximum time we get the records around 400-500 and sometime we get records in thousands.
Code as below.
#SpringBootApplication
#EnableScheduling
#EnableAsync
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
#Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.build();
}
#Bean("ThreadPoolTaskExecutor")
public TaskExecutor getAsyncExecutor() {
final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(8);
executor.setMaxPoolSize(8);
executor.setQueueCapacity(8);
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setThreadNamePrefix("async-");
executor.setRejectedExecutionHandler(new RejectedExecutionHandlerImpl());
executor.initialize();
return executor;
}
}
#Service
public class Main {
#Autowired
private DemoDao dao;
#Autowired
private Asyn asyn;
static int schedulerCount = 0;
#Scheduled(cron = "0/2 * * * * *")
public void schedule() {
System.out.println("++++++++++++++++++++++++++++++++++++Scheduler started schedulerCount : "+schedulerCount+"+++++++++++++++++++++++++++++++++++++"+ LocalDateTime.now());
List<Json> jsonList = new ArrayList<Json>();
List<List<Json>> smallLi = new ArrayList<List<Json>>();
try {
jsonList = dao.getJsonList();
System.out.println("jsonList size : " + jsonList.size());
int count = jsonList.size();
//Creating 8 sublist (8 sublist because thread pool size is 8) from main list(jsonList)
int limit = Math.round(count / 8) + 1;
for (int j = 0; j < count; j += limit) {
smallLi.add(new ArrayList<Json>(jsonList.subList(j, Math.min(count, j + limit))));
}
System.out.println("smallLi : " + smallLi.size());
//After creating 8 sublist, sending sublists with Async method so that 8 threads create and each thread process one sublist asynchronously.
for (int i = 0; i < smallLi.size(); i++) {
asyn.withAsyn(smallLi.get(i), schedulerCount);
}
schedulerCount++;
} catch (Exception e) {
e.printStackTrace();
}
}
#Async("ThreadPoolTaskExecutor")
public void withAsyn(List<Json> li, int schedulerCount) throws Exception {
System.out.println("with start+++++++++++++ schedulerCount " + schedulerCount + ", name : "
+ Thread.currentThread().getName() + ", time : " + LocalDateTime.now() + ", start index : "
+ li.get(0).getId() + ", end index : " + li.get(li.size() - 1).getId());
try {
XSSFWorkbook workbook = new XSSFWorkbook();
XSSFSheet spreadsheet = workbook.createSheet("Data");
XSSFRow row;
for (int i = 0; i < li.size(); i++) {
row = spreadsheet.createRow(i);
Cell cell9 = row.createCell(0);
cell9.setCellValue(li.get(i).getId());
Cell cell = row.createCell(1);
cell.setCellValue(li.get(i).getName());
Cell cell1 = row.createCell(2);
cell1.setCellValue(li.get(i).getPhone());
Cell cell2 = row.createCell(3);
cell2.setCellValue(li.get(i).getEmail());
Cell cell3 = row.createCell(4);
cell3.setCellValue(li.get(i).getAddress());
Cell cell4 = row.createCell(5);
cell4.setCellValue(li.get(i).getPostalZip());
}
FileOutputStream out = new FileOutputStream(new File("C:\\Users\\RK658\\Desktop\\logs\\generated\\"
+ Thread.currentThread().getName() + "_" + schedulerCount + ".xlsx"));
workbook.write(out);
out.close();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("with end+++++++++++++ schedulerCount " + schedulerCount + ", name : "
+ Thread.currentThread().getName() + ", time : " + LocalDateTime.now() + ", start index : "
+ li.get(0).getId() + ", end index : " + li.get(li.size() - 1).getId());
}
I am looking solution that next scheduler should not call until first
scheduler get completed.
You have defined #Service public class Main {...} and by default #Service is an indication for spring to build a singleton. If you have not done anything to modify this, then the expected behavior is for spring to create only a single instance of your class Main in heap memory.
So in this case if you add the synchronized keyword in your method you will allow only 1 thread to be able to execute your method at some time. Every other thread requesting to execute your scheduled method will need to wait until the thread that is already running finishes.
#Scheduled(cron = "0/2 * * * * *")
public synchronized void schedule() { .... }
Example of above solution scenario.
Thread A starts executing method schedule.
2 seconds later while Thread A still executes, Thread B starts and wants to execute the same method.
Thread B will wait outside and will start executing the method only after Thread A has finished execution.
So in the above scenario if 3 schedulers are spawn at close 3 time intervals all of them will wait for execution and maybe this will lead to some bottle neck of your scheduling and might put some heavy load on your resources.
If that is the case another alternative solution would be to cancel Thread B method execution if it arrives while Thread A already executes the same method. This way you will be sure that no bottle neck is built up.
To implement this you can use a ReentrantLock.
#Service
public class Main {
private final ReentrantLock reentrantLock = new ReentrantLock();
....
#Scheduled(cron = "0/2 * * * * *")
public void schedule() {
if (reentrantLock.tryLock()) {
try {
//... all your existing method code
} finally {
reentrantLock.unlock();
}
} else {
//log that the `Thread B` was cancelled if you want, as it requested to execute the method while `Thread A` was already executing.
}
}
}
I believe you can use ShedLock to solve this issue. https://www.baeldung.com/shedlock-spring
https://github.com/lukas-krecan/ShedLock
I'm using KafkaSource to read kafka messages of Events type, as per documentation providing event time extractor is optional for source kafka
KafkaSource<Events> source =
KafkaSource.<Events>builder()
.setProperties(kafkaProperties)
.setBootstrapServers(parameters.get("bootstrap-servers-source"))
.setTopics(parameters.get("source-topic"))
.setGroupId("visit-events-flink-mvp")
.setStartingOffsets(OffsetsInitializer.committedOffsets(OffsetResetStrategy.EARLIEST))
//.setStartingOffsets(OffsetsInitializer.earliest())
.setValueOnlyDeserializer(new EventsDeserializationSchema())
.build();
// event stream from kafka source
DataStream<Events> eventStream =
env.fromSource(source, WatermarkStrategy.forMonotonousTimestamps(), "Kafka Source")
//should be a unique id
.uid("kafka-source");
//stream is keyed based on the anonymousId
DataStream<Events> keyedStream =
eventStream.keyBy(Events::getAnonymousId)
// .process(new KeyedProcessing(Long.parseLong(parameters.get("ttl"))))
.process(new KeyedProcessingWithCallBack(Long.parseLong(parameters.get("ttl"))))
.uid("engager-events-keyed-processing");
In my KeyedProcessingWithCallBack, I'm setting event time timer for 60 secs and the call back is not triggering at all.
My kafka source has 8 partitions and I'm running job with parallelism 1
public void processElement(EngagerEvents value, KeyedProcessFunction<String, EngagerEvents, String>.Context ctx, Collector<String> out) throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(value.getEventString());
System.out.println("time : " +jsonNode.get("EVENT_TIMESTAMP").textValue());
if (anonymousIdHasBeenSeen.value() == null) {
System.out.println("time stamp emitting: " +jsonNode.get("EVENT_TIMESTAMP").textValue());
// key is not available in the state
anonymousIdHasBeenSeen.update(true);
System.out.println("TIMER START TIME: " +ctx.timestamp());
out.collect(value.getEventString());
ctx.timerService().registerEventTimeTimer(ctx.timestamp() + (stateTtl * 1000));
}
}
// not getting triggered
#Override
public void onTimer(long timestamp, OnTimerContext ctx, Collector<String> out)
throws Exception {
// triggers after ttl has passed
System.out.println("Call back triggered : time : " +timestamp + " value : " +anonymousIdHasBeenSeen.value());
anonymousIdHasBeenSeen.clear();
}
TEST Simulator code which will send event with anonymousId=111 with different event time stamp
try {
for (int i = 0; i < 500; i++) {
String[] anonymousId = {"111"};
String key = String.valueOf(new Random().nextInt(10));
ProducerRecord<String, String> record = new ProducerRecord<>(
"flink-visits-mvp-test-source",
key,
// getEvent(UUID.randomUUID().toString() + "-" +Thread.currentThread().getName() , event[new Random().nextInt(1)]));
// getEvent(anonymousId[new Random().nextInt(1)], event[new Random().nextInt(1)]));
getEvent(anonymousId[new Random().nextInt(1)],
System.currentTimeMillis(),
event));
//System.out.println(record.value().toString());
producer.send(record);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
Am I doing something wrong here ? Why is my event time timer call back not trgiggering ?
I also experience the same error with Flink V1.16. The processElement method is invoked as expected however, observed that ctx.timerService().currentWatermark() always print as -9223372036854775808. onTimer method never invoked with 60 seconds timer.
With lots of trial and error I found that invoking env.setParallelism() method resolve the issue.
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setParallelism(1);
After fix, the currentWatermark() method return correct watermark time and onTimer method is invoked every 60 seconds.
Here is the log entries before fix:
Event Time = 1669610765000, End Of Window Time = 1669610819999,
current water mark time = -9223372036854775808
Event Time = 1669610807000, End Of Window Time = 1669610819999,
current water mark time = -9223372036854775808
Here is the log entries after fix:
Event Time = 1669610393000, End Of Window Time = 1669610399999,
current water mark time = 1669610387999
Event Time = 1669610450000, End Of Window Time = 1669610459999,
current water mark time = 1669610435999
I want it fire a job once on every 1st day in a every month that should be any week day.But if it is sunday on 1st do not fire the job just postpone it to fire at 2nd day and immediately terminate schedule.
Again do the same process of scheduling for next months also.?
Below is the code to schedule it for every 55 seconds for testing envrironment and how about the destroy method?
QuartzPlugin.java
public class QuartzPlugin implements PlugIn {
#Override
public void destroy() {
}
#Override
public void init(ActionServlet servlet, ModuleConfig config) throws ServletException {
// define the job and tie it to our MyJob class
JobDetail job = JobBuilder.newJob(SchedulerJob.class).withIdentity("anyJobName", "group1").build();
try {
// Cron Trigger the job to run now, and then repeat every 55 secs
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("anyTriggerName", "group1")
.withSchedule(CronScheduleBuilder.cronSchedule("0/55 * * * * ?"))
//Every 1 minute "0 0/1 * 1/1 * ? *"
// Every 55 Sec "0/55 * * * * ?"
// Every 5 Sec "0/5 * * * * ?"
// Every month 1st day "0 10 1-7 * *"
.build();
// Grab the Scheduler instance from the Factory
Scheduler scheduler = new StdSchedulerFactory().getScheduler();
// and start it off
scheduler.start();
// Tell quartz to schedule the job using our trigger
scheduler.scheduleJob(job, trigger);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
}
SchedularJob.java
public class SchedulerJob implements Job {
private ArrayList mapList = new ArrayList();
private DAO dao = new DAO();
private HSSFWorkbook workbook = new HSSFWorkbook();
private FileOutputStream fileOut = null;
public void execute(JobExecutionContext context) throws JobExecutionException {
String dirpath = System.getProperty("user.dir").replaceAll("bin", "") + "webapps/it_email/sent/email_"
+ new SimpleDateFormat("dd-MM-yyyy").format(new Date());
String genStatus = generateExcel(dirpath);
System.out.println("genStatus::" + genStatus);
if (genStatus.equals("Y")) {
String text = "Please find attached case list dated "
+ new SimpleDateFormat("dd-MM-yyyy").format(new Date()) + "."
+ "\n\n Microsoft Excel is required to open this attachment.\n\n"
+ "Registrar Judicial,High Court of Judicature at Hyderabad.\n\n"
+ "This email is System generated. Please do not reply to this email ID.\n\n "
+ "Disclaimer:The NIC/High Court is not responsible for non-delivery of emails.";
String subject = "HIGH COURT:Availability of Case Data.";
String to = "ajaythakur2014#gmail.com";
String filetype = ".xls";
sendEmail(to, subject, text, dirpath, filetype);
System.out.println("For every 55 secs");
}
}
When the above code is run i sporadically get the
Oracle 9i Production Environment : IO Exception : The Network Adapter could not establish the connection
i guess creating more no of new connections every 55 seconds.
Could be useful this link ,where there is the official documentation :MonthlyTrigger
I'm new with Quartz.
I succeeded to install it and run it.
But I have an error when I run it for the second time because the job already exists with this identification.
Here my code :
public void scheduleJobs() throws Exception {
try {
int i = 0;
scheduler = new StdSchedulerFactory().getScheduler();
JobKey job1Key = JobKey.jobKey("job"+i, "my-jobs"+i);
JobDetail job1 = JobBuilder
.newJob(SimpleJob.class)
.withIdentity(job1Key)
.build();
TriggerKey tk1 = TriggerKey.triggerKey("trigger"+i, "my-jobs"+i);
Trigger trigger1 = TriggerBuilder
.newTrigger()
.withIdentity(tk1)
.withSchedule(CronScheduleBuilder.dailyAtHourAndMinute(11, 25))
.build();
scheduler.start(); // start before scheduling jobs
scheduler.scheduleJob(job1, trigger1);
i++;
printJobsAndTriggers(scheduler);
} catch (SchedulerException e) {
LOG.error("Error while creating scheduler", e);
}
}
I tried to use an integer i to change the name but it does not work.
Do you have any idea how can I fix it?
Many thanks.
You can:
check if the "job key" already exists, and remove the existing job before creating a new one:
scheduler.deleteJob(job1Key);
or create a new job with another key (in your case, each time you execute scheduleJobs(), variable i has the same value (0)
or just re-use the same job (why would you create a new job if the old one is still good)
or use the RAM Job Store, which does not persist jobs in database (each time you will use your software, you will have an empty job store)
It really depends on what you want to do with your jobs!
Check for existing job before scheduling:
JobDetail job;
SimpleTrigger trigger;
//Create your trigger and job
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.start();
if (scheduler.checkExists(job.getKey())){
scheduler.deleteJob(job.getKey());
}
scheduler.scheduleJob(job, trigger);
This is not a direct answer to the specific code listed in the question, but I didn't notice it when searching elsewhere and thought this might be useful for future readers:
If you're in a situation where you have an existing Job but just want to add a new Trigger, you can call:
scheduler.ScheduleJob(trigger);
and it will add the Trigger to the Job without trying to recreate the Job. The only trick is that you have to make sure the Trigger's JobKey is correct.
My overall code for this interaction looks roughly like:
IJobDetail job; // Handed in
ITrigger trigger; // Handed in
// Keeping track of this because we need to know later whether it's new or not
var newJob = job == null;
if (newJob)
{
job = JobBuilder.Create<TargetJob>()
.WithIdentity([whatever])
[.OtherConfiguration()]
.Build();
}
var trigger = TriggerBuilder
.Create()
.WithIdentity([whatever])
// ** Gotcha #1: Make sure it's linked to the job **
.ForJob(job.Key)
[.OtherConfiguration()]
.Build();
if (newJob)
{
_scheduler.ScheduleJob(job, trigger);
}
else
{
// ** Gotcha #2: Make sure you don't reschedule the job **
_scheduler.ScheduleJob(trigger);
}
If anyone of you are facing the same issue and your solution is in C#. This is how you can fix this error.
This is where we configure the scheduler.
public async Task StartAsync(CancellationToken cancellationToken) {
try {
var scheduler = await GetScheduler();
var serviceProvider = GetConfiguredServiceProvider();
scheduler.JobFactory = new CustomJobFactory(serviceProvider);
await scheduler.Start();
await ConfigureDailyJob(scheduler);
}
catch(Exception ex) {
_logger.Error(new CustomConfigurationException(ex.Message));
}
}
This is how we can configure the Job, please be noted that we are checking whether the job is already there, and if the await scheduler.CheckExists(dailyJob.Key) returns true, we delete that job info and create a new one with the same key.
private async Task ConfigureDailyJob(IScheduler scheduler) {
var dailyJob = GetDailyJob();
if (await scheduler.CheckExists(dailyJob.Key)) {
await scheduler.DeleteJob(dailyJob.Key);
_logger.Info($ "The job key {dailyJob.Key} was already existed, thus deleted the same");
}
await scheduler.ScheduleJob(dailyJob, GetDailyJobTrigger());
}
There are the supporting private functions.
private IJobDetail GetDailyJob() {
return JobBuilder.Create < IDailyJob > ().WithIdentity("dailyjob", "dailygroup").Build();
}
private ITrigger GetDailyJobTrigger() {
return TriggerBuilder.Create().WithIdentity("dailytrigger", "dailygroup").StartNow().WithSimpleSchedule(x = >x.WithIntervalInHours(24).RepeatForever()).Build();
}
You can get the complete source code from this GitHub repository.
You can create new jobs by taking i as a static int. And instead of "job"+i it would be "job"+ Integer.toString(i) . It worked for me.
Please can any one forward me the sample code related. Cause i tried a lot and on internet no useful info or links i can found related to it.
Thanks in Advance
This might be a workaround. But it works!
In your scheduler, have a default thread running every 1 minute (Or interval of your choice) that pings a file or DB for any changes.
The scheduler should be refreshed if the scheduler finds an entry in the DB.
From your JSP, on click of a button, create a relevant entry in the DB.
While pinging the DB, if the scheduler finds an entry, then it will do the necessary action.
Code snippet
// Default constructor.
public Scheduler()throws SchedulerException, Exception
{
try
{
SchedulerFactory sf = new StdSchedulerFactory();
sche = sf.getScheduler();
sche.start();
if(sche.isShutdown())
{
SendAlerts.sendMsgToGroup("Scheduler Failed To Start at "+sdtf3.format(new Date())+" hrs.",defaultMsgGroup);
logger.fatal("Scheduler Failed To Start At = " + sdtf1.format(new Date()) );
}
else
{
SendAlerts.sendMsgToGroup("Scheduler started at "+sdtf3.format(new Date())+" hrs.",SchStartAlertGroup);
logger.fatal("Scheduler Started At = " + sdtf1.format(new Date()) );
}
sysdate = new Date();
readFromDBAndConfigureSchedules();
while (true)
{
if(sche.isShutdown())
{
SendAlerts.sendMsgToGroup("Scheduler Failed To Start at "+sdtf3.format(new Date())+" hrs.",defaultMsgGroup);
logger.fatal("Scheduler Failed To Start At = " + sdtf1.format(new Date()) );
}
else
{
logger.info("Scheduler is Running. Table Last Pinged at : "+sdtf1.format(sysdate));
}
/*
-----------------
IN THE CHECK DB TABLE METHOD, HANDLE REQUESTS FOR STOP, PAUSE, RE-SCHEDULE ETC
------------------
*/
SchRunJob.checkDBTable();
// Loop will repeat every 1 hour = 60 minutes * 60 seconds = 3600 seconds
Thread.sleep (3600 * 1000);
} // End of while Start Flag is Y
} // End of try block
catch (Exception e)
{
SendAlerts.sendMsgToGroup( "Fatal Exception Caught.Scheduler Shut Down at " + sdtf1.format(new Date()),defaultMsgGroup);
logger.fatal("Fatal Exception Caught.Scheduler Shut Down at " + sdtf1.format(new Date()));
e.printStackTrace();
System.exit(0);
}
} // End of default constructor**