Quartz Scheduler - Updating only the JobDataMap, between jobs - java

I have a Quartz Job that I can schedule with some Cron Trigger.
ReportSchedule reportSchedule = ... // my object
JobDetail jobDetail = new JobDetail(reportSchedule.getScheduleName(),
reportSchedule.getScheduleGroup(),
ExtendedReportJob.class /* my job */);
jobDetail.getJobDataMap().put("reportSchedule", reportSchedule);
jobDetail.setDescription(reportSchedule.getScheduleDescription());
CronTrigger trigger = ...; // depends on the report schedule
scheduler.scheduleJob(jobDetail, trigger);
This code successfully writes the job and details to a database.
The reportSchedule object contains specific parameters that are required for the job. However, I may want to change the parameters.
I can do this with
scheduler.deleteJob(name, group);
scheduler.scheduleJob(jobDetail, trigger);
// where jobDetail.getJobDataMap() has the updated reportSchedule
Doing this, however, will trigger the job right away since the trigger depends on the report schedule and I don't want to change it (I want to keep original date). So my question: Is there any way to modify the JobDetail or JobDataMap between jobs without changing the Trigger?
I'm using Quartz 1.6.0.

The solution is simple enough, just have to know the API.
The Scheduler class has the following method
Scheduler#addJob(JobDetail, boolean);
In which the passed JobDetail will overwrite the previous one if the boolean argument is set to true.
So
// name and group are the primary key of the job detail
final JobDetail jobDetail = new JobDetail(name, group, ExtendedReportJob.class);
// reportSchedule is the object I've previously modified
jobDetail.getJobDataMap().put(ORStatics.REPORT_SCHEDULE, reportSchedule);
jobDetail.setDescription(reportSchedule.getScheduleDescription());
// overwrite the previous job, however retaining the triggers
scheduler.addJob(jobDetail, true);
will update the job detail in persistent storage. Since the primary key for the table containing the JobDetail will remain the same, we don't need to change the triggers. They will still execute it as scheduled.

What about getting the trigger with getTrigger(String triggerName, String triggerGroup) and store it in a variable. Then create a new job with your new jobDataMap and use the old trigger?

Related

Fetch Spring Batch Job Execution with specific Job parameter

I want to fetch the lastJobExecution with specific job parameter.
Scenario:
I want to store userEmail as a job parameter, and then fetch last job execution of that user :
Map<String, JobParameter> parameters = new HashMap<>();
parameters.put("userEmail", new JobParameter("something#xyz.com", true));
JobParameters jobParameters = new JobParameters(parameters);
jobRepository.getLastJobExecution("jobName", jobParameters)
Issue in above approach:
If I only use put only userEmail as a job parameter, same user wont be able to trigger another job once previous job is finished, as error: A job instance already exists with given job parameters.
So I am planning to add userEmail + startTime as job parameter. So same user can trigger multiple jobs.
However, now I want to fetch last job execution of that user, I need both userEmail + startTime
Map<String, JobParameter> parameters = new HashMap<>();
parameters.put("userEmail", new JobParameter("something#xyz.com", true));
parameters.put("startTime", new JobParameter(123L, true));
JobParameters jobParameters = new JobParameters(parameters);
jobRepository.getLastJobExecution("jobName", jobParameters)
But I dont have startTime when fetching last job execution of that user.
Is there any way to fetch last job execution with only 1 job parameter?
Or do I need to write my own JdbcTemplate-based DAO implementation to run the select query ?
Tried using long way, like fetch all job executions by job name and then filter.
But this is quite inefficient way.
Identifying job parameters are hashed together to produce a key that is used to identify job instances. So there is no direct way to fetch the last job execution of a job instance with a single parameter. You need to fetch is yourself with a custom SQL query or programmatically by filtering job executions as you did.
That said, it feels like this a job parameters design issue, rather than a limitation in Spring Batch. The choice of start time a job parameter is not suitable to your case as it is not constant in time, hence you can't have it when fetching the last job execution. You need to find a way to uniquely identify job instances which allows you to have all information needed when fetching executions.

Spring Boot - Quartz Scheduler - Retrieve all jobs details

I am using below code to get the all Job Details and display them in my UI. But it is taking too long ( Around 35 seconds ) to fetch the job details ( around 150 Quartz jobs ) from QUARTZ using JDBC data store ( Oracle DB).
Is there any alternate ways to speed up the task?
Any API support available for pagination from Quartz?
//All below code can be written using Java 8 Streams as well. Broke down the code to understand which //operation is taking time
Scheduler scheduler = schedulerFactoryBean.getScheduler();
Set<TriggerKey> triggerKeys = scheduler.getTriggerKeys(GroupMatcher.triggerGroupEquals(groupName)); //groupName - my group name - filtering by groupname
Iterator iterator = triggerKeys .iterator();
//This while block is taking around 12 seconds for around 150 jobs
while(iterator.hasNext()){
TriggerKey triggerKey = (TriggerKey) iterator.next();
if(scheduler.getTriggerState(triggerKey).equals(TriggerState.NONE)){
iterator.remove();
}
Map<TriggerKey, MyPOJO> myJobMap = new HashMap();
//This for loop is taking around 22 seconds for around 150 jobs
for(TriggerKey key : triggerKeys){
Trigger trigger = scheduler.getTrigger(key);
JobDataMap jobDataMap = scheduler.getJobDetail(trigger.getJobKey()).getJobDataMap();
MyPOJO myPOJO = jobDataMap.get("MYJOBPOJO");
myJobMap.put(key, myPOJO);
}
I have gone through the Quartz documentation but did not find any specific details on how to improve this read operation performance

Quartz 2.x, How to get Trigger Type?

I am using quartz 2.x version.
I need get column TRIGGER_TYPE from QRTZ_TRIGGERS tables.
using API, how to get TRIGGER_TYPE?
This is my code:
for (String group : scheduler.getTriggerGroupNames()) {
for (TriggerKey triggerKey : scheduler.getTriggerKeys(GroupMatcher.<TriggerKey>groupEquals(group))) {
Trigger trigger = scheduler.getTrigger(triggerKey(triggerKey.getName(), triggerKey.getGroup()));
System.out.println(scheduler.getSchedulerName());
System.out.println(triggerKey.getName());
System.out.println(triggerKey.getGroup());
System.out.println(trigger.getJobKey());
//job name
//job group
System.out.println(trigger.getDescription());
System.out.println(trigger.getNextFireTime());
System.out.println(trigger.getPreviousFireTime());
System.out.println(trigger.getPriority());
System.out.println(scheduler.getTriggerState(triggerKey(triggerKey.getName(), triggerKey.getGroup())));
//trigger type
System.out.println(trigger.getStartTime());
System.out.println(trigger.getEndTime());
System.out.println(trigger.getCalendarName());
System.out.println(trigger.getMisfireInstruction());
}
}
There are 2 Trigger types, SimpleTrigger and CronTrigger.
Maybe look at their API. You will probably get clues there on how to distinguish between the two.
The TRIGGER_TYPE information in the QRTZ_TRIGGERS is reflected at runtime in the specific Java type of the Trigger implementation:
CalendarIntervalTriggerImpl -> TTYPE_CAL_INT,
CronTriggerImpl -> TTYPE_CRON,
DailyTimeIntervalTriggerImpl -> TTYPE_DAILY_TIME_INT and
SimpleTriggerImpl -> TTYPE_SIMPLE.
There is also a default trigger type for custom Trigger types: TTYPE_BLOB.
Note that if you really want to access that information at runtime, you are better off using the following code:
TriggerPersistenceDelegate tDel = new StdJDBCDelegate().findTriggerPersistenceDelegate(trigger);
String type = TTYPE_BLOB;
if(tDel != null)
type = tDel.getHandledTriggerTypeDiscriminator();

Why Quartz scheduler's unscheduleJob is deleting both trigger and job detail?

Im trying to execute the following quartz scheduler code in the a cluster environment.
scheduler.unscheduleJob("genericJobTrigger", "DEFAULT");
where as
Scheduler scheduler = (Scheduler) context.getBean("scheduler");
JobDetail genericJob = (JobDetail) context.getBean("genericJob");
CronTrigger genericJobTrigger = (CronTrigger) context.getBean("genericJobTrigger");
Above piece of code is deleting entries from trigger and job detail. It supposed to remove only trigger right?
Why Quartz scheduler's unscheduleJob is deleting both trigger and job detail?
durability is set true to Jobs to avoid deleting the JOBS when Triggers are deleted.
Whenever you are creating an object of JobDetail then set storeDurably(), refer the below example:
return JobBuilder.newJob(ScheduledJob.class)
.setJobData(jobDataMap)
.withDescription("job executes at specified frequency")
.withIdentity(UUID.randomUUID().toString(), "email-jobs")
.storeDurably() //This will not allow to delete automatially
.build();
Also you can verify it by checking the value of IS_DURABLE column in jobDetails table.

How can I disable jobs in the Quartz JDBCJobStore?

What is the best way to disable a job in the JDBCJobStore without deleting it's job or trigger records and without wiping the cron expression?
Use scheduler.pauseJob() or scheduler.pauseTrigger().
Alternatively you can use the following SQL script:
UPDATE QRTZ_TRIGGERS SET TRIGGER_STATE = "PAUSED"
Use the pauseJob or pauseJobGroup methods of JobStore.

Categories

Resources