Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting data from a running job in Quartz.net

Tags:

c#

quartz.net

I am trying to create a job in Quartz.net that will monitor the state of all the other jobs and regularly update a log file. It only gets data back from a job once that job has completed execution, but I am trying to get on the fly information of the state of the job.

I wrote as simple a test job as possible and the test half works (which is frustrating because I can't tell what is different in the actual code). This is the test code:

The jobs

[PersistJobDataAfterExecution]
[DisallowConcurrentExecution]
class SimpleFeedbackJob : IInterruptableJob
{
    private DateTime _lastRun;
    public string LastRun { get { return _lastRun.ToString(); } }
    private string _status;

    public void Interrupt()
    {
    }

    public void Execute(IJobExecutionContext context)
    {
        _status = "working";
        _lastRun = DateTime.Now;

        JobDataMap jobData = context.JobDetail.JobDataMap;
        jobData["time"] = LastRun;
        jobData["status"] = _status;

        DateTime n = DateTime.Now.AddSeconds(5);
        while (DateTime.Now < n) { }
        //Thread.Sleep(5000);

        _status = "idle";
        jobData["status"] = _status;
    }
}

public class LogUpdaterJob : IInterruptableJob
{
    private IScheduler _scheduler = TaskManager.Scheduler; //This is the same scheduler that will call this task :/
    private string _filepath = Configs.BasePath + @"Logs\log.txt";

    public void Execute(IJobExecutionContext context)
    {
        Func<string, string> UpdatedLineData
           = name =>
           {
               JobKey jobKey = _scheduler.GetJobKeys(GroupMatcher<JobKey>.GroupContains("test")).Where(k => k.Name == name).First();
               IJobDetail job = _scheduler.GetJobDetail(jobKey);
               ITrigger trigger = _scheduler.GetTriggersOfJob(jobKey).First();

               string status = job.JobDataMap.Get("time") as string;
               string time = job.JobDataMap.Get("status") as string;

               return string.Format("{0,-25} {1,-25}", time, status);
           };

        List<string> lines = new List<string>();
        lines.Add(UpdatedLineData("feedback_test"));
        File.WriteAllLines(_filepath, lines);
    }

    public void Interrupt()
    {
    }
}

Relevant extracts from TaskScheduler

private static IScheduler _scheduler = StdSchedulerFactory.GetDefaultScheduler();
public static IScheduler Scheduler { get { return _scheduler; } }

public void Run()
{
    _scheduler.Start();

    IJobDetail feedbackJob = JobBuilder.Create<SimpleFeedbackJob>()
                                       .WithIdentity("feedback_test", "test")
                                       .UsingJobData("time", "")
                                       .UsingJobData("status", "")
                                       .Build();

    ITrigger feedbackTrigger = TriggerBuilder.Create()
                                             .WithIdentity("feedback_test", "test")
                                             .WithSimpleSchedule(x => x.WithIntervalInSeconds(10)
                                                                       .RepeatForever())
                                             .Build();

    IJobDetail loggerJob = JobBuilder.Create<LogUpdaterJob>()
                                     .WithIdentity("LogUpdater", "Admin")
                                     .Build();

    ITrigger loggerTrigger = TriggerBuilder.Create()
                                           .WithIdentity("LogUpdater", "Admin")
                                           .WithSimpleSchedule(x => x.WithIntervalInSeconds(1)
                                                                     .RepeatForever())
                                           .Build();

    _scheduler.ScheduleJob(feedbackJob, feedbackTrigger);
    _scheduler.ScheduleJob(loggerJob, loggerTrigger);
}

So this does output some data to log.txt, it gets the last run time correct but it only ever displays a status of "idle" where I think it should be "working" half the time. In otherwords I would like the job data to be written to and accessible while the job is still running.

Is it possible to get data back from the job midway through the jobs Execute() like this?

like image 933
Dan Avatar asked Oct 10 '14 11:10

Dan


People also ask

What is JobDataMap in Quartz?

Holds state information for Job instances. JobDataMap instances are stored once when the Job is added to a scheduler. They are also re-persisted after every execution of StatefulJob instances. JobDataMap instances can also be stored with a Trigger .

How do I Unschedule a Quartz job?

We can unschedule a Job by calling the unschedule() method of the Scheduler class and passing the TriggerKey . If the related job does not have any other triggers, and the job is not durable, then the job will also be deleted.

How do you schedule multiple jobs using Quartz?

If you want to schedule multiple jobs in your console application you can simply call Scheduler. ScheduleJob (IScheduler) passing the job and the trigger you've previously created: IJobDetail firstJob = JobBuilder. Create<FirstJob>() .

What is misfire in Quartz?

A misfire occurs if a persistent trigger “misses” its firing time because of the scheduler being shutdown, or because there are no available threads in Quartz's thread pool for executing the job. The different trigger types have different misfire instructions available to them.


1 Answers

It looks like job data changes are not available until the job has finished. So instead use a dedicated data structure for the purpose of monitoring the job status. In the following example I have exposed the status information using a simple public static property StatusInfo which is available to the logging job at any time.

One more minor change: I have replaced WriteAllLines with AppendAllLines.

class StatusInfo
{
    public DateTime LastRun;
    public string Status;
}

[PersistJobDataAfterExecution]
[DisallowConcurrentExecution]
class SimpleFeedbackJob : IInterruptableJob
{
    public static StatusInfo StatusInfo;

    static SimpleFeedbackJob()
    {
        SetStatus("idle");
    }

    public void Interrupt()
    {
    }

    public void Execute(IJobExecutionContext context)
    {
        SetStatus("working");

        Thread.Sleep(5000);

        SetStatus("idle");
    }

    private static void SetStatus(string status)
    {
        StatusInfo = new StatusInfo
            {
                LastRun = DateTime.Now,
                Status = status
            };
    }
}

class LogUpdaterJob : IInterruptableJob
{
    private string _filepath = @"D:\Temp\Logs\log.txt";

    public void Execute(IJobExecutionContext context)
    {
        List<string> lines = new List<string>();
        var statusInfo = SimpleFeedbackJob.StatusInfo;
        lines.Add(String.Format("{0,-25} {1,-25}",
            statusInfo.LastRun,
            statusInfo.Status));
        File.AppendAllLines(_filepath, lines);
    }

    public void Interrupt()
    {
    }
}
like image 67
Rafał Rutkowski Avatar answered Oct 09 '22 17:10

Rafał Rutkowski