Dawood Awan
Dawood Awan

Reputation: 7328

Call a function after the Job has completed Full Execution

We are using Quartz.Net to trigger jobs on a schedule in a Windows Service.

I have a situation where I have to Trigger a job every 5 minutes from Start DateTime till End DateTime.

After the job is completed we need to calculate the Next Start DateTime and Next End DateTime and save to the DB -

For this I tried to override the JobListener which has a method: JobWasExecuted

public class xPTJobListener : JobListenerSupport
{
    public override string Name { get { return "xPTJobListener"; } }

    public override void JobWasExecuted(IJobExecutionContext context, JobExecutionException jobException)
    {

        var dataMap = context.MergedJobDataMap;
        var schedule = (MyDTO)dataMap["Schedule"];

        using (var logger = new xPTLogger())
        {
            logger.LogMessage(MessageType.Information, string.Format("Inside JobWasExecuted() - [{0}] - ", schedule.Id));
        }

        base.JobWasExecuted(context, jobException);
    }
}

and also the TriggerComplete in the TriggerListener

public class xPTTriggerListener : TriggerListenerSupport
{
    public override string Name { get { return "xPTTriggerListener"; } }

    public override void TriggerComplete(ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode)
    {

        var dataMap = context.MergedJobDataMap;
        var schedule = (MyDTO)dataMap["Schedule"];

        using (var logger = new xPTLogger())
        {
            logger.LogMessage(MessageType.Information, string.Format("Inside Trigger Complete - [{0}] - ", schedule.Id));
        }


        base.TriggerComplete(trigger, context, triggerInstructionCode);

    }
}

But the problem with above methods is that they are both executed each time the job is called.

So if I have a Job which runs from 12:01 AM and ends 12:02 AM every 5 seconds - Both these methods get called 12 times

What I need is to call a method only once after the One Job iteration has Ended - (After the Job is executed 12 Times)?

How do I do this in Quartz?

EDIT

Creating the Triggers

public static ITrigger GenerateTrigger(RouteMonitorScheduleDTO routeSchedule, double fGmtOffset, xPTLogger logger)
{
    ITrigger trigger = null;

    switch (routeSchedule.ScheduleInfo.PeriodType)
    {
        case PeriodTypeEnum.Once:
            trigger = TriggerBuilder.Create()
                        .WithIdentity(string.Format("trigger_{0}", routeSchedule.RouteScheduleId), DefaultGroup)
                        .StartAt(routeSchedule.DepartureDateTime)
                        .WithSimpleSchedule(s => s.WithIntervalInMinutes(5))
                        .EndAt(routeSchedule.ArrivalDateTime.AddMinutes(5))
                        .Build();
            break;
        case PeriodTypeEnum.Daily:
        case PeriodTypeEnum.WeekDays:
        case PeriodTypeEnum.Weekly:
        case PeriodTypeEnum.Monthly:
            var schedule = routeSchedule.ScheduleInfo;        
            var cronExpresion = xPTCronBuilder.GenerateCronExpression(
                                    schedule.PeriodType,                         
                                    schedule.ScheduleStringValue, 
                                    fGmtOffset,             
                                    routeSchedule.DepartureDateTime,
                                    routeSchedule.ArrivalDateTime.AddMinutes(5), 5);
            trigger = TriggerBuilder.Create()
                        .WithIdentity(string.Format("trigger_{0}", routeSchedule.RouteScheduleId), DefaultGroup)
                        .WithCronSchedule(cronExpresion)
                        .Build();
            break;
    }

    return trigger;
}

EDIT Trigger with Cron:

trigger = TriggerBuilder.Create()
.WithIdentity(string.Format("trigger_{0}", 1), "Group1")
.WithCronSchedule("0 0-45/5 7-7 ? * TUE,WED *").Build();

As you can see from above cron expression it will run from 7 AM to 7:45 AM every 5 minutes every Tuesday and Wednesday.

So 1 iteration is 7AM to 7:45 AM on Tuesday, the Next is 7 AM to 7:45 on Wednesday. I need to call a function after each Iteration has completed.

So let's say that when the Last Trigger is fired for 7:45 AM on Tuesday - I need to call the function.

Upvotes: 4

Views: 4865

Answers (3)

Stefan Steiger
Stefan Steiger

Reputation: 82176

I use JobListener for this.
TriggerListener is unreliable, as it doesn't get called if the trigger is triggered manually.

Example:

// Quartz.IJobDetail job1 = Quartz.JobBuilder.Create() .... .Build();
// Quartz.ITrigger trigger = Quartz.TriggerBuilder.Create() .... .Build();

this.m_scheduler.ListenerManager.AddJobListener(new SimpleJobListener(),
    Quartz.Impl.Matchers.KeyMatcher<JobKey>.KeyEquals(new JobKey(job1.Key.Name, job1.Key.Group)
    )
);


this.m_scheduler.ListenerManager.AddTriggerListener(new SimpleTriggerListener(),
    Quartz.Impl.Matchers.KeyMatcher<TriggerKey>.KeyEquals(new TriggerKey(trigger.Key.Name, trigger.Key.Group)
    )
);

Listeners:

using Quartz;


namespace ReportMailer
{


    public class SimpleTriggerListener
        : ITriggerListener
    {
        protected string m_jobName;

        string ITriggerListener.Name => this.m_jobName;


        public SimpleTriggerListener(string name)
        {
            this.m_jobName = name;
        }

        public SimpleTriggerListener()
            : this("Job_" + System.Guid.NewGuid().ToString())
        { }



        System.Threading.Tasks.Task ITriggerListener.TriggerComplete(
            ITrigger trigger, 
            IJobExecutionContext context, 
            SchedulerInstruction triggerInstructionCode,
            System.Threading.CancellationToken cancellationToken)
        {
            System.Console.WriteLine("TriggerComplete");
            return System.Threading.Tasks.Task.CompletedTask;
        }

        System.Threading.Tasks.Task ITriggerListener.TriggerFired(
            ITrigger trigger, 
            IJobExecutionContext context, 
            System.Threading.CancellationToken cancellationToken)
        {
            System.Console.WriteLine("TriggerFired");
            return System.Threading.Tasks.Task.CompletedTask;
        }

        System.Threading.Tasks.Task ITriggerListener.TriggerMisfired(
            ITrigger trigger, 
            System.Threading.CancellationToken cancellationToken)
        {
            System.Console.WriteLine("TriggerMisfired");
            return System.Threading.Tasks.Task.CompletedTask;
        }

        System.Threading.Tasks.Task<bool> ITriggerListener.VetoJobExecution(
            ITrigger trigger, 
            IJobExecutionContext context, 
            System.Threading.CancellationToken cancellationToken)
        {
            System.Console.WriteLine("VetoJobExecution");
            return System.Threading.Tasks.Task.FromResult(false);
        }
    } // End Class SimpleTriggerListener 



    public class SimpleJobListener
        : IJobListener
    {

        protected string m_jobName;

        string IJobListener.Name
        {
            get
            {
                return this.m_jobName;
            }
        }


        public SimpleJobListener(string name)
        {
            this.m_jobName = name;
        }

        public SimpleJobListener()
            : this("Job_" + System.Guid.NewGuid().ToString())
        { }



        System.Threading.Tasks.Task IJobListener.JobExecutionVetoed(
            IJobExecutionContext context, 
            System.Threading.CancellationToken cancellationToken)
        {
            System.Console.WriteLine("JobExecutionVetoed");
            return System.Threading.Tasks.Task.CompletedTask;
        }

        System.Threading.Tasks.Task IJobListener.JobToBeExecuted(
            IJobExecutionContext context, 
            System.Threading.CancellationToken cancellationToken)
        {
            System.Console.WriteLine("JobToBeExecuted");
            return System.Threading.Tasks.Task.CompletedTask;
        }

        System.Threading.Tasks.Task IJobListener.JobWasExecuted(
            IJobExecutionContext context, 
            JobExecutionException jobException, 
            System.Threading.CancellationToken cancellationToken)
        {
            System.Console.WriteLine("JobWasExecuted");
            return System.Threading.Tasks.Task.CompletedTask;
        }

    } // End Class SimpleJobListener 


}

Upvotes: 0

Murat Yıldız
Murat Yıldız

Reputation: 12022

What about creating another job triggered once in a minute for the given period by using the StartTime or EndTime as global values?

In addition to this, you could also check the EndTime value before calling your action method. In this case you execute the action if the current time is equal to or near to DateTime.Now() or something similar to that:

//...
if(endtime == DateTime.Now())
{
    //call your action
}

Hope this helps...

Upvotes: 0

Evk
Evk

Reputation: 101463

If I understand your problem correctly, you can do this using ITriggerListener in the following way:

public class xPTTriggerListener : TriggerListenerSupport {
    public override string Name
    {
        get { return "xPTTriggerListener"; }
    }

    public override void TriggerComplete(ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode) {
        if (triggerInstructionCode == SchedulerInstruction.DeleteTrigger) {
            // means this trigger won't be fired again - now recalculate your dates in database
        }
        base.TriggerComplete(trigger, context, triggerInstructionCode);
    }
}

Upvotes: 2

Related Questions