Apex passing parameters to Batch job during scheduling

Here it the use case:

You have 1 job that you want to run weekly and monthly but the monthly job also has to generate a notification. You don’t need to create two classes but can pass a parameter to the schedule to know it is a weekly or monthly job.

The batch Job class that accepts constructor parameter jobRunFrequency
global class AccountBatchJob implements System.Schedulable, Database.Batchable<SObject>, Database.Stateful, Database.AllowsCallouts {

	private static final String RUN_WEEKLY_JOB = 'RUN_WEEKLY_JOB';
	//This is the key that needs to be used to generate notifications for Monthly 
	private static final String RUN_MONTHLY_JOB = 'RUN_MONTHLY_JOB';
	private String jobRunFrequency;

	String query = 'Select Id, FirstName, LastName from Account';

	public AccountBatchJob(){
		this.jobRunFrequency = RUN_WEEKLY_JOB;

	public AccountBatchJob(String jobRunFrequency){
		this.jobRunFrequency = jobRunFrequency;

        global Database.QueryLocator start(Database.BatchableContext BC) {
		return Database.getQueryLocator(query);

    global void execute(Database.BatchableContext BC, List<Account> accounts) {
     if (RUN_MONTHLY_JOB.equalsIgnoreCase(jobRunFrequency)){

Test class for batch Job passing parameter check if it is the Monthly job

	Database.executeBatch(new AccountBatchJob('RUN_MONTHLY_JOB'), 1);

Test class Scheduler Job to check it if is the Monthly job

	String jobId = System.schedule('AccountBatchJob', '0 0 0 15 3 ? 2022', new AccountBatchJob('RUN_MONTHLY_JOB'));
	CronTrigger ct = [SELECT Id, CronExpression, TimesTriggered, NextFireTime FROM CronTrigger WHERE id = :jobId];
	System.assertEquals('0 0 0 15 3 ? 2022', ct.CronExpression);

Spring Quartz Service Implementation

Spring Service implementation of Quartz

package com.example.service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;

import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.example.job.QuartzDeleteJob;
import com.example.job.QuartzInsertJob;

public class JobManagerService {

	public static final String BATCHINSERT = "QuartzInsertJob";
	public static final String BATCHDELETE = "QuartzDeleteJob";
	public static final String BATCHUPDATE = "QuartzUpdateJob";
	private Logger logger = LoggerFactory.getLogger(JobManagerService.class);
	private Scheduler scheduler = null;
	private Map<String, JobDetail> jobDetails = new HashMap<String, JobDetail>();
	private Map<String, Trigger> jobTriggers = new HashMap<String, Trigger>();
	private Map<String, JobKey> jobKeys = new HashMap<String, JobKey>();
	private Map<String, String> cronExpressions = new HashMap<String, String>();
	private List<String> cronOutput = new ArrayList<String>();
	private boolean successfullyInitialized = false;

	public void initialize() {
		try {
			initializeJob(QuartzInsertJob.class, BATCHINSERT);
			initializeJob(QuartzDeleteJob.class, BATCHDELETE);
			successfullyInitialized = true;
		} catch (SchedulerException e) {
			logger.warn("exception during initialization");
	private void initializeScheduler() throws SchedulerException {
		logger.info("initializing scheduler...");
		scheduler = StdSchedulerFactory.getDefaultScheduler();
		logger.info("scheduler initialized and started");

	public JobDetail buildJob(Class<?> jobClass, String jobName){
		JobDetail jobDetail =  JobBuilder.newJob((Class<Job>) jobClass).withIdentity(jobName).storeDurably(true).build();
		jobDetails.put(jobName, jobDetail);
		return jobDetail;
	public void getJobKeyAndCheckExist(JobDetail jobDetail, String jobName) throws SchedulerException{
		JobKey jobKey = jobDetail.getKey();
		jobKeys.put(jobName, jobKey);
		if (scheduler.checkExists(jobKey)) {
			jobDetail = scheduler.getJobDetail(jobKey);
			List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobDetail.getKey());
			if (triggers.size() > 0) {
				if (triggers.size() > 1) {
					resetTriggers(jobName, triggers);
				} else {
					Trigger trigger = triggers.get(0);
					jobTriggers.put(jobName, trigger);
					cronExpressions.put(jobName, ((CronTrigger) trigger).getCronExpression());
		} else {
			scheduler.addJob(jobDetail, false);
	private void initializeJob(Class<?> jobClass, String jobName) throws SchedulerException {
		logger.info("initializing <{}>", jobName);
		JobDetail jobDetail = buildJob(jobClass, jobName);
		getJobKeyAndCheckExist(jobDetail, jobName);
		logger.info("<{}> initialized", jobName);
	private void resetTriggers(String jobName, List<? extends Trigger> triggers) throws SchedulerException {			
		for (Trigger trigger : triggers) {
	public String checkAndUnscheduleTrigger(String jobName) {
		Trigger trigger = jobTriggers.get(jobName);
		if (trigger != null) {
			TriggerKey triggerKey = trigger.getKey();
			logger.info("unscheduling <{}>", triggerKey);
			try {
				jobTriggers.put(jobName, null);
				return triggerKey + " successfully unscheduled";
			} catch (SchedulerException e) {
				logger.error("exception unscheduling <{}>", triggerKey);
		} else {
			logger.info("trigger for <{}> not found", jobName);
		return "exception unscheduling";
	public List<String> checkAndScheduleCronExpression(String jobName, String triggerName, String cronExpression) {
		Trigger trigger = jobTriggers.get(jobName);
		if (trigger == null) {
			trigger = TriggerBuilder.newTrigger()
			try {
				cronOutput.add("scheduling "  + jobName + " with cron expression " + cronExpression);
				cronOutput.add("successfully scheduled: " + jobName);
				jobTriggers.put(jobName, trigger);
				cronExpressions.put(jobName, cronExpression);
			} catch (SchedulerException e) {
				cronOutput.add("exception scheduling: "+ jobName);
		} else {
			cronOutput.add("trigger already exists for: " + jobName);
		return cronOutput;
	public boolean isSuccessfullyInitialized() {
		return successfullyInitialized;

	public String retrieveCronExpression(String jobName) {
		return cronExpressions.get(jobName);
	public Map<String, String> getCronExpressions(){
		return cronExpressions;
	public Map<String, Trigger> getJobTriggers(){
		return jobTriggers;
	public Map<String, JobDetail> getJobDetails(){
		return jobDetails;
	public Map<String, JobKey> getJobKeys(){
		return jobKeys;
	public List<String> getCurrentlyExecutingJobs() throws SchedulerException{
		List<String> jobDescriptions = new ArrayList<String>();
		for (JobExecutionContext runningJobs : scheduler.getCurrentlyExecutingJobs()){
		return jobDescriptions;

Example of an Insert Quartz job to insert records into a database using jpa.

package com.example.job;

import java.util.List;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.example.jpa.JpaConfiguration;
import com.example.model.Customer;
import com.example.service.CustomerService;

public class QuartzDeleteJob implements Job  {

	public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
	        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
	        CustomerService customerService = applicationContext.getBean(CustomerService.class);
	        List<Customer> listOfCustomersToDelete = customerService.getPaginatedCustomer(0, 2);