Search code examples
c#quartz-scheduler

Using Quartz JobDataMap to Pass Parameters to a Job on Execution


I have a scheduled task that runs daily at a specific time. However, I am able to perform ad hoc runs of this job as well. I am attempting to pass through parameters to the job in order to distinguish between the scheduled and ad hoc runs by only passing through values when an ad hoc run is performed, but the data map is empty every time.

Schedule Setup

public class ScheduledTriggers
{
  private static IJobDetail job;
  private static IScheduler quartzScheduler;
  private static ITrigger trigger;

  public ScheduledTriggers()
  {
    try
    {
      // Grab the Scheduler instance from the Factory
      NameValueCollection props = new NameValueCollection
      {
        { "quartz.serializer.type", "binary" }
      };
      StdSchedulerFactory factory = new StdSchedulerFactory(props);
      quartzScheduler = factory.GetScheduler().Result;
  
      // and start it off
      quartzScheduler.Start();
  
      // define the job and tie it to our job class
      job = JobBuilder.Create<TheJob>()
        .WithIdentity("TheJob", "TheGroup")
        .Build();
      
      // Trigger the job to run as scheduled
      SetupTriggers();
  
      // Tell quartz to schedule the job using our trigger
      if (trigger != null)
      {
        quartzScheduler.ScheduleJob(job, trigger);
      }
      else
      {
        MessageLogger.LogError("ERROR");
      }
    }
    catch (SchedulerException se)
    {
      MessageLogger.LogError("An error occurred while setting up the Quartz scheduler.", se);
    }
  }
  
  private void SetupTriggers()
  {
    trigger = null;
  
    TriggerBuilder builder = TriggerBuilder
      .Create()
      .WithIdentity("TheTrigger", "TheGroup");
  
    DateTimeOffset now = DateTimeOffset.UtcNow;
    builder
    .StartAt(now)
    .WithSimpleSchedule
    (ss =>
      ss
      .WithIntervalInHours(24)
      .RepeatForever()
    );
  
    trigger = builder.Build();
  }

  public void AdHocRun()
  {
    job.JobDataMap.Put("Scheduled", false);
    job.JobDataMap.Put("DT", DL.Format(DateTimeOffset.UtcNow)); // DL.Format returns a string of format YYYY-MM-DD hh:mm:ss +zz:zz
  
    quartzScheduler.TriggerJob(job.Key);
  }
}

Inside TheJob.Execute Implementation

...
object scheduledTaskObj;

context.JobDetail.JobDataMap.TryGetValue("Scheduled", out scheduledTaskObj);
Boolean scheduledTask = scheduledTaskObj != null ? (Boolean)scheduledTaskObj : true;
MessageLogger.LogDebug($"Task scheduled: {scheduledTask}");

context.MergedJobDataMap.TryGetValue("Scheduled", out scheduledTaskObj);
scheduledTask = scheduledTaskObj != null ? (Boolean)scheduledTaskObj : true;
MessageLogger.LogDebug($"[Merged] Task scheduled: {scheduledTask}");

context.JobDetail.JobDataMap.TryGetValue("DT", out scheduledTaskObj);
MessageLogger.LogDebug($"Date time: {scheduledTaskObj?.ToString()}");

context.MergedJobDataMap.TryGetValue("DT", out scheduledTaskObj);
MessageLogger.LogDebug($"[Merged] Date time: {scheduledTaskObj?.ToString()}");
...

The output text is as follows:

Task scheduled: True
[Merged] Task scheduled: True
Date time:
[Merged] Date time:

instead of an expected output of something along the lines of

Task scheduled: False
[Merged] Task scheduled: False
Date time: 2024-08-14 16:00:00 +00:00
[Merged] Date time: 2024-08-14 16:00:00 +00:00

Is there something that I am missing in the setup of the job or am I maybe using the JobDataMap incorrectly?


Solution

  • I have a found a solution to this.

    Essentially, create a new JobDataMap object, populate this new object with the information that needs to be sent through and pass this new object when triggering the job.

    public void AdHocRun()
    {
      JobDataMap map = new JobDataMap();
      map.Put("Scheduled", false);
      map.Put("DT", DL.Format(DateTimeOffset.UtcNow)); // DL.Format returns a string of format YYYY-MM-DD hh:mm:ss +zz:zz
      
      quartzScheduler.TriggerJob(job.Key, map);
    }
    

    This information can then be retrieved through the MergedJobDataMap object from the context.

    context.MergedJobDataMap.TryGetValue("Scheduled", out scheduledTaskObj);
    

    I have not tested this with non-primitive type items as I am using Json strings to deal with these, as recommended by other StackOverflow answers.