22

I've setup my AdoJobStore on the server and all my jobs are running perfectly. Now I am writing a remote client to manage all my jobs.

Scheduling new jobs is straightforward enough, but I can't seem to retrieve a list of existing jobs in version 2.0. All the resources I found did something like the following.

var groups = sched.JobGroupNames;
for (int i = 0; i < groups.Length; i++)
{
    string[] names = sched.GetJobNames(groups[i]);
    for (int j = 0; j < names.Length; j++)
    {
        var currentJob = sched.GetJobDetail(names[j], groups[i]);
    }
}

The problem I'm facing is that GetJobNames has been removed, and looking at the source code, has been moved to the base class JobStoreSupport, which JobStoreCMS inherits from. The method has however been marked as protected, so it is inaccessible from the outside.

How would one go about retrieving a job list in 2.0?

André Haupt
  • 3,294
  • 5
  • 32
  • 57
  • Hey do u have any examples on editing schedules? Im new to this and having a nightmare! please help – Kalpa-W Apr 08 '15 at 06:27

4 Answers4

49

You can use fetch a list of executing jobs:

var executingJobs = sched.GetCurrentlyExecutingJobs();
foreach (var job in executingJobs)
{
    // Console.WriteLine(job.JobDetail.Key);
}

or fetch all the info about scheduled jobs (sample console application):

private static void GetAllJobs(IScheduler scheduler)
{
    IList<string> jobGroups = scheduler.GetJobGroupNames();
    // IList<string> triggerGroups = scheduler.GetTriggerGroupNames();

    foreach (string group in jobGroups)
    {
        var groupMatcher = GroupMatcher<JobKey>.GroupContains(group);
        var jobKeys = scheduler.GetJobKeys(groupMatcher);
        foreach (var jobKey in jobKeys)
        {
            var detail = scheduler.GetJobDetail(jobKey);
            var triggers = scheduler.GetTriggersOfJob(jobKey);
            foreach (ITrigger trigger in triggers)
            {
                Console.WriteLine(group);
                Console.WriteLine(jobKey.Name);
                Console.WriteLine(detail.Description);
                Console.WriteLine(trigger.Key.Name);
                Console.WriteLine(trigger.Key.Group);
                Console.WriteLine(trigger.GetType().Name);
                Console.WriteLine(scheduler.GetTriggerState(trigger.Key));
                DateTimeOffset? nextFireTime = trigger.GetNextFireTimeUtc();
                if (nextFireTime.HasValue)
                {
                    Console.WriteLine(nextFireTime.Value.LocalDateTime.ToString());
                }

                DateTimeOffset? previousFireTime = trigger.GetPreviousFireTimeUtc();
                if (previousFireTime.HasValue)
                {
                    Console.WriteLine(previousFireTime.Value.LocalDateTime.ToString());
                }
            }
        }
    } 
}

I've used the code found here.

UPDATE:

If someone is interested a sample code can be downloaded from my GitHub repository.

Someone asked how to get a list of job completed.
I don't think there's an easy way for that.
The only option which comes to mind is using a job (or trigger) listener.

I've uploaded a sample on github where my main program can receive events of completed jobs.

LeftyX
  • 35,328
  • 21
  • 132
  • 193
  • 1
    The 2nd block of code was exactly what I was looking for. Thanks! – Matt Dell Apr 29 '13 at 16:40
  • 1
    In that example, what is "sched" and where does it come from? – wexman Oct 07 '14 at 10:23
  • It doesn't work in case the jobs and triggers are loaded from the .config file. Any solution? – Rwiti Dec 18 '14 at 16:24
  • @Rwiti: It does work. You can try it yourself [repo](https://github.com/Leftyx/QuartzNetXmlJobs). Cheers. – LeftyX Dec 19 '14 at 12:03
  • @LeftyX How would you get a list of jobs that have already completed? – Howiecamp Jul 06 '15 at 15:24
  • @Howiecamp: I guess you have to use listeners for that. Check my [repository](https://github.com/Leftyx/QuartzNetWithJobListener) on GitHub. – LeftyX Jul 07 '15 at 09:24
  • @leftyx Now I understand that Quartz keeps no history of its own and that if I do want to track ongoing history I can do so myself within the listeners. I just was trying to find out if Quartz kept it natively. – Howiecamp Jul 07 '15 at 14:02
  • @Howiecamp: I don't think it can but I must say I haven't followed the evolution of the framework as I switched to a different one. – LeftyX Jul 07 '15 at 15:41
  • @leftyx - Actually now I am certain (based on research and your answer) that preserving job history is not an automatic function of Quartz. So I definitely agree that you can do it yourself and the listener is the best place. – Howiecamp Jul 07 '15 at 19:37
  • @LeftyX In the above GetAllJobs code how would you access the jobdata for each of the jobs (normally available in the execution context)? – Matthew Jul 19 '15 at 03:20
  • @Matt: If I understand your question, when you have an `IJobDetail` you have access to all the info related to a job. – LeftyX Jul 19 '15 at 10:15
  • @LeftyX - As part of reporting on scheduled+currently running jobs (like `GetAllJobs`) I wanted to include `JobDataMap` info for the jobs. I know (per your comment) that you need a `JobDetail` to get the `JobDataMap`, and in a job's `Execute()` method or a listener you can grab the `JobDetail` from the `JobExecutionContext` as follows: `JobDataMap dataMap = context.JobDetail.JobDataMap;` Where I'm not clear is how/if I can get this info as part of the 'GetAllJobs' listing, because I don't have access to the `JobExecutionContext`. I feel like I *should* be able to get it since it does exist... – Matthew Jul 20 '15 at 14:55
  • 1
    @Matt: Info for the `JobDataMap` can be found in [IJobDetail](https://github.com/quartznet/quartznet/blob/master/src/Quartz/IJobDetail.cs). In the function above at some point you can find `var detail = scheduler.GetJobDetail(jobKey);`. `detail` now references an object of type `IJobDetail` so you should be able to do `JobDataMap dataMap = detail.JobDataMap;` – LeftyX Jul 21 '15 at 09:51
  • @LeftyX Perfect... It was right there in front of me and I didn't see it. Thanks a lot - it works like a charm. – Matthew Jul 22 '15 at 17:50
  • @Matt: Glad I've helped. Cheers. – LeftyX Jul 22 '15 at 18:08
  • @LukeHutton: Thanks. Fixed. Cheers. – LeftyX Aug 27 '15 at 11:03
  • Don't use var groupMatcher = GroupMatcher.GroupContains(group); If one groupname contains the other you will get faulty data. e.g. If one group is named 'orders' and the other 'preorders' you will have match on both in one case. – Mattias Örtenblad Apr 23 '21 at 12:36
9

Since Quartz.NET version 2.2.1 you can make use of GroupMatcher<>.AnyGroup(), here implemented as an extension method to IScheduler:

public static List<IJobDetail> GetJobs(this IScheduler scheduler)
{
    List<IJobDetail> jobs = new List<IJobDetail>();

    foreach (JobKey jobKey in scheduler.GetJobKeys(GroupMatcher<JobKey>.AnyGroup()))
    {
        jobs.Add(scheduler.GetJobDetail(jobKey));
    }

    return jobs;
}

This will get you a list of IJobDetails for every scheduled job.

KeyNone
  • 8,745
  • 4
  • 34
  • 51
5

If you want to get the Repeat Interval, Repeat Count etc cast the ITrigger to ISimpleTrigger

private void LogInfo(IScheduler scheduler) 
{
    log.Info(string.Format("\n\n{0}\n", Scheduler.GetMetaData().GetSummary()));

    var jobGroups = scheduler.GetJobGroupNames();
    var builder = new StringBuilder().AppendLine().AppendLine();

    foreach (var group in jobGroups)
    {
        var groupMatcher = GroupMatcher<JobKey>.GroupContains(group);
        var jobKeys = scheduler.GetJobKeys(groupMatcher);

        foreach (var jobKey in jobKeys)
        {
            var detail = scheduler.GetJobDetail(jobKey);
            var triggers = scheduler.GetTriggersOfJob(jobKey);

            foreach (ITrigger trigger in triggers)
            {
                builder.AppendLine(string.Format("Job: {0}", jobKey.Name));
                builder.AppendLine(string.Format("Description: {0}", detail.Description));
                var nextFireTime = trigger.GetNextFireTimeUtc();
                if (nextFireTime.HasValue)
                {
                    builder.AppendLine(string.Format("Next fires: {0}", nextFireTime.Value.LocalDateTime));
                }
                var previousFireTime = trigger.GetPreviousFireTimeUtc();
                if (previousFireTime.HasValue)
                {
                    builder.AppendLine(string.Format("Previously fired: {0}", previousFireTime.Value.LocalDateTime));
                }
                var simpleTrigger = trigger as ISimpleTrigger;
                if (simpleTrigger != null)
                {
                    builder.AppendLine(string.Format("Repeat Interval: {0}", simpleTrigger.RepeatInterval));
                }
                builder.AppendLine();
            }
        }
    }

    builder.AppendLine().AppendLine();
    log.Info(builder.ToString); 
}
superlogical
  • 14,332
  • 9
  • 66
  • 76
2

For Quartz.NET version 3.0 you can use

this will show you all running jobs and triggers in quartz.net 3.x

using Quartz;
using Quartz.Impl;
using Quartz.Impl.Matchers;

    class Program
    {
            var allTriggerKeys = scheduler.GetTriggerKeys(GroupMatcher<TriggerKey>.AnyGroup());
            foreach (var triggerKey in allTriggerKeys.Result)
            {
             var triggerdetails =   scheduler.GetTrigger(triggerKey);
             var Jobdetails = scheduler.GetJobDetail(triggerdetails.Result.JobKey);

                Console.WriteLine("IsCompleted -" + triggerdetails.IsCompleted + " |  TriggerKey  - " + triggerdetails.Result.Key.Name + " Job key -" + triggerdetails.Result.JobKey.Name);

            }
}

I've used the code found here.

Hasan_Naser
  • 204
  • 3
  • 13