Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Quartz.NET - Jobs don't run?

I'm attempting to implement Quartz.NET as a Windows Service in C#. My jobs are not triggering when I expect them to trigger... at all, actually, as far as I can tell?

I have My Job schedule running starting on the next even minute after the and running "minutely". However, when the next minute comes, I cannot seem to tell if anything actually runs.

I would assume that when my job runs, a CLI window would pop on job execution, and the Console operations would be visible, (I even put a Console.ReadKey() in there to ensure the window isn't opening and closing so fast I can't see it), but as far as I can tell the schedule is simply not executing jobs.

I noticed that all the times are in UTC, and that the StartTimeUtc will be set to the UTC time which is +6 hours from my local computer time, but I would also assume that the Quartz scheduler handles that by calculating execution time from my TimeZone setting, though I have no way that I know of to confirm that, or to confirm the ACTUAL times that my schedule is set for.

I imagine there's some way to setup the Common Logging assembly and utilize it to help me know what my status is, but I have yet to figure out what to do with that to enable a log of any sort for feedback from my Windows Service, aside from writing to the event log I created for it.

My OnStart function of my windows service

protected override void OnStart(string[] args)
    {
        eventLog.WriteEntry("--- STARTING eLoyalty Scheduler Service ---");

        // construct a scheduler factory
        ISchedulerFactory schedFact = new StdSchedulerFactory();

        // get a scheduler
        IScheduler sched = schedFact.GetScheduler();

        // construct job info
        JobDetail jobDetail = new JobDetail("eLoyaltySchedulerService", null, typeof(PortalSchedulerJob));
        jobDetail.JobDataMap["jobSays"] = "eLoyalty Scheduler Service Executing!";
        jobDetail.JobDataMap["myStateData"] = new ArrayList(); 

        // fire every minute
        Trigger trigger = TriggerUtils.MakeMinutelyTrigger();

        // start on the next even minute
        trigger.StartTimeUtc = TriggerUtils.GetEvenMinuteDate(DateTime.UtcNow);

        // name it
        trigger.Name = "NextEvenMinute";

        // schedule it
        sched.ScheduleJob(jobDetail, trigger);

        // start the schedule
        sched.Start();

        eventLog.WriteEntry("--- STARTED eLoyalty Scheduler Service ---");
    }

My Job's Execute() function is as follows:

public void Execute(JobExecutionContext context)
    {
        try
        {
            string instName = context.JobDetail.Name;
            string instGroup = context.JobDetail.Group;
            JobDataMap dataMap = context.MergedJobDataMap;
            string jobSays = dataMap.GetString("jobSays");
            ArrayList state = (ArrayList)dataMap["myStateData"];
            state.Add(DateTime.UtcNow);

            Console.WriteLine("Instance {0} of PortalSchedulerJob says: {1} @ {2}", instName, jobSays, DateTime.UtcNow);
            Console.ReadKey();
        }
        catch (JobExecutionException Ex)
        {
            throw Ex;
        }
    }

If you can help me figure out how to troubleshoot my ACTUAL schedule activity, I may be able to solve this on my own... ?

like image 563
Rimer Avatar asked Nov 24 '10 17:11

Rimer


2 Answers

In Quartz.NET tasks, you must only raise JobExecutionException exceptions: Quartz.net- Lesson 3:

The Job.Execute(..) Method Finally, we need to inform you of a few details of the IJob.Execute(..) method. The only type of exception that you are allowed to throw from the execute method is the JobExecutionException. Because of this, you should generally wrap the entire contents of the execute method with a 'try-catch' block. You should also spend some time looking at the documentation for the JobExecutionException, as your job can use it to provide the scheduler various directives as to how you want the exception to be handled.

Instead of:

catch (JobExecutionException Ex)
{
   throw Ex;
}

Do something like this:

catch (Exception err)
{
    // Only allow JobExecutionException exceptions to be thrown...
    throw new Quartz.JobExecutionException(err);
}

You can then handle the Exception centrally:

_globalJobListener = new GlobalJobListener();
sched.AddGlobalJobListener(_globalJobListener);


public class GlobalJobListener : Quartz.IJobListener
{
    public GlobalJobListener()
    {
    }

    public virtual string Name
    {
        get { return "MainJobListener"; }
    }

    public virtual void JobToBeExecuted(JobExecutionContext context)
    {       
    }

    public virtual void JobWasExecuted(JobExecutionContext inContext, JobExecutionException inException)
    {
        if (inException != null)
        {
            // Log/handle error here
        }
    }


    public virtual void JobExecutionVetoed(JobExecutionContext inContext)
    {

    }
}
like image 146
Keith Blows Avatar answered Oct 02 '22 02:10

Keith Blows


You could always run your Windows service in the console when you're debugging:

static class Program
{
    static void Main()
    {
        var servicesToRun = new ServiceBase[] 
            { 
                new CassetteDeckService() 
            };

        if (Environment.UserInteractive)
        {
            var type = typeof(ServiceBase);
            const BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic;
            var method = type.GetMethod("OnStart", flags);

            foreach (var service in servicesToRun)
            {
                method.Invoke(service, new object[] { null });
            }

            Console.WriteLine("Service Started!");
            Console.ReadLine();

            method = type.GetMethod("OnStop", flags);

            foreach (var service in servicesToRun)
            {
                method.Invoke(service, null);
            }
            Environment.Exit(0);
        }
        else
        {
            ServiceBase.Run(servicesToRun);
        }
    }
}

Just make sure to change the application type to Console Application in the properties of your Windows service project (this won't affect it running as a Windows service when it is not run in interactive mode).

like image 22
brimble2010 Avatar answered Oct 02 '22 01:10

brimble2010