Quartz.net: Run a job for specific interval of time - c#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Quartz;
using Quartz.Impl;
using Quartz.Job;
using ConsoleApplication2;
namespace Lesson1
{
class Program
{
static void Main(string[] args)
{
//Create the scheduler factory
ISchedulerFactory schedulerFactory = new StdSchedulerFactory();
//Ask the scheduler factory for a scheduler
IScheduler scheduler = schedulerFactory.GetScheduler();
//Start the scheduler so that it can start executing jobs
scheduler.Start();
// Create a job of Type WriteToConsoleJob
IJobDetail job = JobBuilder.Create(typeof(WriteToConsoleJob)).Build();
ITrigger trigger = TriggerBuilder.Create().WithDailyTimeIntervalSchedule(s => s.WithIntervalInMinutes(15).OnMondayThroughFriday().StartingDailyAt(TimeOfDay.HourAndMinuteOfDay(9, 0))).Build();
scheduler.ScheduleJob(job, trigger);
//A nice way to stop the scheduler, waiting for jobs that are running to finish
scheduler.Shutdown(true);
}
}
}
I have created a test job and its working fine for weekdays repeating after 15 minutes starting at 0900 hours but i want to run it for specific interval of time i.e. 0900 to 1500 hours.
And i don't want to use CronTrigger for this.

Add an EndingDailyAt call:
ITrigger trigger = TriggerBuilder
.Create()
.WithDailyTimeIntervalSchedule(s =>
s.WithIntervalInMinutes(15)
.OnMondayThroughFriday()
.StartingDailyAt(TimeOfDay.HourAndMinuteOfDay(9, 0))
.EndingDailyAt(TimeOfDay.HourAndMinuteOfDay(15, 0)))
.Build();

Related

Show next job execution scheduled time

I was wondering if Quartz.Net has a way to tell (or better write in the logs) on the next execution... I mean, I have got a job that runs at 10:00 AM and it's scheduled to run every two hours... is there a way I can write something as Next run on 12:00AM? or do I have to parse the cron expression, then add it to the current date?
Thanks in advance
Not sure what logger you are using, but this approach should work with any logger that you can create instances of. Create instance of logger and pass it to job via JobDataMap and then use it inside of job. IJobExecutionContext.NextFireTimeUtc will tell you next execution time which you can write to a logger
using System;
using System.Threading.Tasks;
using NLog;
using Quartz;
using Quartz.Impl;
namespace QuartzSampleApp
{
public class Program
{
private static async Task Main(string[] args)
{
var logger = LogManager.GetCurrentClassLogger();
StdSchedulerFactory factory = new StdSchedulerFactory();
IScheduler scheduler = await factory.GetScheduler();
await scheduler.Start();
IJobDetail job = JobBuilder.Create<HelloJob>()
.WithIdentity("job1", "group1")
.Build();
job.JobDataMap["logger"] = logger; // add logger to job data map
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity("trigger1", "group1")
.StartNow()
.WithSimpleSchedule(x => x
.WithIntervalInSeconds(10)
.RepeatForever())
.Build();
await scheduler.ScheduleJob(job, trigger);
await Task.Delay(TimeSpan.FromSeconds(60));
await scheduler.Shutdown();
Console.WriteLine("Press any key to close the application");
Console.ReadKey();
}
// simple log provider to get something to the console
}
public class HelloJob : IJob
{
public async Task Execute(IJobExecutionContext context)
{
await Console.Out.WriteLineAsync("Greetings from HelloJob!");
var logger = context.JobDetail.JobDataMap["logger"] as ILogger;
logger.Log(LogLevel.Info, "Next job execution at " + context.NextFireTimeUtc);
}
}
}

While continuously running Timer based event programming there was a jump in the events than expected. Why does it happen?

I will invoke a method called 'start' with Time Interval as '1 second'.
I wish to continue invoking certain actions in every 1 second interval. But while running it works by performing those actions according to Time Interval given. But when I observed the logs closely I could see intermittently it pauses for some time and then again starts.
Is there any problem with the async programming here?
Example logs
Starting to send periodic Telemetry at 09:15:31.753
Starting to send periodic Telemetry at 09:15:32.753
Starting to send periodic Telemetry at 09:15:36.753
See it skipped 4 seconds here
PublisherClass
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Test.Helpers
{
public static class PublisherClass{
public static List < System.Timers.Timer > SendPeriodicTimerObjs {
get;
set;
} = new List < System.Timers.Timer > ();
public static async Task PublishToMethod(string methodName, string message) {
try {
string topic;
switch (methodName) {
case "start":
var sendPeriodicObj = new SendPeriodicTelemetry();
sendPeriodicObj.periodicTimer = new System.Timers.Timer();
SendPeriodicTimerObjs.Add(sendPeriodicObj.periodicTimer);
if (methodName == "start") {
var timeIntervel = 1000;
sendPeriodicObj.periodicTimer.Interval = timeIntervel;
sendPeriodicObj.SetTimer(timeIntervel, sendPeriodicObj.periodicTimer);
await CommonMethods.AckMethod(CommonMethods.listMessage, CommonMethods.requestId, MethodNames.start);
}
break;
}
}
}
}
}
SendPeriodicTelemetry
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
namespace Test.Helpers
{
public class SendPeriodicTelemetry
{
public void SetTimer(Timer timer)
{
timer.Elapsed += SendPeriodic;
timer.AutoReset = true;
timer.Enabled = true;
}
public async void SendPeriodic(Object source, ElapsedEventArgs e)
{
Console.WriteLine("Starting to send periodic Telemetry at {0:HH:mm:ss.fff}", e.SignalTime);
await SendPeriodicTimeSeries(TimeSeriesTopic, TelemetrySingle, Configuration);
await SendPeriodicAlarm(AlarmTopic, AlarmSingle);
await SendPeriodicEvent(EventTopic, EventSingle);
}
}
}
P.S: See the code works fine continuously invoking the three actions on 1 second interval. It never stops. But problem is as stated it intermittently pauses for certain seconds and again re-starts. I have no idea why it happens.
"... although we enabled our timer to trigger every one second, the event handler was delayed in order to handle other activity of
the CPU. Server-based timers are dependent on the operating system's
multithreading character on which our code runs, and the program must
obey the CPU priority rules when using these timers." - c-sharpcorner.com
You want to search for "high resolution timer" or "accurate metronome timer".
You might end up in a position where you have to decide what is more important: the computers other demanding computations, or pin-point accurate telemetry. You can live with delayed telemetry, optimise those other computations, increase hardware requirements, or some combination of these things.

C# Schedule a Function using Quartz.net (or alternatives)

I have a C# service and I need to run a function once a week.
I have a working C# service which currently is running on a timer every 60 seconds.
Please see below a section of the services OnStart function:
// Set up a timer to trigger.
System.Timers.Timer timer = new System.Timers.Timer
{
Interval = 60000 //*1000; // 60 second
};
timer.Elapsed += delegate {
// Runs the code every 60 seconds but only triggers it if the schedule matches
Function1();
};
timer.Start();
The above code calls Function1() every 60 seconds and I am checking it in Function1 if the current dayofweek and time matches the schedule and if it does than execute the rest of the function.
Although this does work it not the most elegant way IMO.
I have tried using Quartz.net as it was looking promising but when I used all the examples available online (questions answered some 7 years ago in 2012), it is showing as an error in visual studio:
using System;
using Quartz;
public class SimpleJob : IJob
{
public void Execute(IJobExecutionContext context)
{
throw new NotImplementedException();
}
}
This is erroring
(Error CS0738 'SimpleJob' does not implement interface member 'IJob.Execute(IJobExecutionContext)'. 'SimpleJob.Execute(IJobExecutionContext)' cannot implement 'IJob.Execute(IJobExecutionContext)' because it does not have the matching return type of 'Task'.)
but this does not:
public Task Execute(IJobExecutionContext context)
{
throw new NotImplementedException();
}
Could someone give a current working example of a job scheduled through Quartz.net for a beginner?
Or using another elegant method than Quartz.net in a C# service?
First of all we need to implement a job implementation. For example:
internal class TestJob : IJob
{
public Task Execute(IJobExecutionContext context)
{
Console.WriteLine("Job started");
return Task.CompletedTask;
}
}
Now we need to write a method which will return a Scheduler of Quartz :
static async Task TestScheduler()
{
// construct a scheduler factory
NameValueCollection props = new NameValueCollection
{
{ "quartz.serializer.type", "binary" }
};
StdSchedulerFactory factory = new StdSchedulerFactory(props);
// get a scheduler
IScheduler sched = await factory.GetScheduler();
await sched.Start();
// define the job and tie it to our HelloJob class
IJobDetail job = JobBuilder.Create<TestJob>()
.WithIdentity("myJob", "group1")
.Build();
// Trigger the job to run now, and then every 40 seconds
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity("myTrigger", "group1")
.StartNow()
.WithSimpleSchedule(x => x
.WithIntervalInMinutes(1)
.RepeatForever())
.Build();
await sched.ScheduleJob(job, trigger);
}
and in the Main method of the Program we will need to write following code:
static async Task Main()
{
Console.WriteLine("Test Scheduler started");
await TestScheduler();
Console.ReadKey();
}
Now this will keep executing after every minute.
Hope it helps.

Configuring quartz.net scheduler in .net

I have an application in .Net framework and I'm using quartz scheduler. I need to configure quartz.
Now I have one method which is fired every 15 minutes. These method is used to do some work with database. I want, in case, that work of procedure is complete, then start waiting period and after that period again start these database method.
For procedure there will be maximum time which cannot be longer. For examplpe 60 minutes. Do you have any ideas how to configure length of working procedure, how to stop when work is finished and how to define waiting time between?
// configure Quartz
var stdSchedulerProperties = new NameValueCollection
{
{ "quartz.threadPool.threadCount", "10" },
{ "quartz.jobStore.misfireThreshold", "60000" }
};
var stdSchedulerFactory = new StdSchedulerFactory(stdSchedulerProperties);
var scheduler = stdSchedulerFactory.GetScheduler().Result;
scheduler.Start();
// create job and specify timeout
IJobDetail job = JobBuilder.Create<JobWithTimeout>()
.WithIdentity("job1", "group1")
.UsingJobData("timeoutInMinutes", 60)
.Build();
// create trigger and specify repeat interval
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity("trigger1", "group1")
.StartNow()
.WithSimpleSchedule(x => x.WithIntervalInMinutes(15).RepeatForever())
.Build();
// schedule job
scheduler.ScheduleJob(job, trigger).Wait();
/// <summary>
/// Implementation of IJob. Represents the wrapper job for a task with timeout
/// </summary>
public class JobWithTimeout : IJob
{
public Task Execute(IJobExecutionContext context)
{
return Task.Run(() => Execute(context));
}
public void Execute(IJobExecutionContext context)
{
Thread workerThread = new Thread(DoWork);
workerThread.Start();
context.JobDetail.JobDataMap.TryGetValue("timeoutInMinutes", out object timeoutInMinutes);
TimeSpan timeout = TimeSpan.FromMinutes((int)timeoutInMinutes);
bool finished = workerThread.Join(timeout);
if (!finished) workerThread.Abort();
}
public void DoWork()
{
// do stuff
}
}

Quartz.net setup in an asp.net website

I've just added quartz.net dll to my bin and started my example. How do I call a C# method using quartz.net based on time?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Quartz;
using System.IO;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if(SendMail())
Response.write("Mail Sent Successfully");
}
public bool SendMail()
{
try
{
MailMessage mail = new MailMessage();
mail.To = "test#test.com";
mail.From = "sample#sample.com";
mail.Subject = "Hai Test Web Mail";
mail.BodyFormat = MailFormat.Html;
mail.Body = "Hai Test Web Service";
SmtpMail.SmtpServer = "smtp.gmail.com";
mail.Fields.Clear();
mail.Fields.Add("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate", "1");
mail.Fields.Add("http://schemas.microsoft.com/cdo/configuration/sendusername", "redwolf#gmail.com");
mail.Fields.Add("http://schemas.microsoft.com/cdo/configuration/sendpassword", "************");
mail.Fields.Add("http://schemas.microsoft.com/cdo/configuration/smtpserverport", "465");
mail.Fields.Add("http://schemas.microsoft.com/cdo/configuration/smtpusessl", "true");
SmtpMail.Send(mail);
return (true);
}
catch (Exception err)
{
throw err;
}
}
}
Here I am just sending a mail on page load. How do I call SendMail() once in a day at a given time (say 6.00 AM) using quartz.net? I don't know how to get started. Should I configure it in my global.asax file? Any suggestion?
Did you try the quartz.net tutorial?
Since your web app might get recycled/restarted, you should probably (re-)intialize the quartz.net scheduler in the Application_Start handler in global.asax.cs.
Update (with complete example and some other considerations):
Here's a complete example how to do this using quartz.net. First of all, you have to create a class which implements the IJobinterface defined by quartz.net. This class is called by the quartz.net scheduler at tne configured time and should therefore contain your send mail functionality:
using Quartz;
public class SendMailJob : IJob
{
public void Execute(JobExecutionContext context)
{
SendMail();
}
private void SendMail()
{
// put your send mail logic here
}
}
Next you have to initialize the quartz.net scheduler to invoke your job once a day at 06:00. This can be done in Application_Start of global.asax:
using Quartz;
using Quartz.Impl;
public class Global : System.Web.HttpApplication
{
void Application_Start(object sender, EventArgs e)
{
ISchedulerFactory schedFact = new StdSchedulerFactory();
// get a scheduler
IScheduler sched = schedFact.GetScheduler();
sched.Start();
// construct job info
JobDetail jobDetail = new JobDetail("mySendMailJob", typeof(SendMailJob));
// fire every day at 06:00
Trigger trigger = TriggerUtils.MakeDailyTrigger(06, 00);
trigger.Name = "mySendMailTrigger";
// schedule the job for execution
sched.ScheduleJob(jobDetail, trigger);
}
...
}
That's it. Your job should be executed every day at 06:00. For testing, you can create a trigger which fires every minute (for example). Have a look at the method of TriggerUtils.
While the above solution might work for you, there is one thing you should consider: your web app will get recycled/stopped if there is no activity for some time (i.e. no active users). This means that your send mail function might not be executed (only if there was some activity around the time when the mail should be sent).
Therefore you should think about other solutions for your problem:
you might want to implement a windows service to send your emails (the windows service will always be running)
or much easier: implement your send mail functionality in a small console application, and set up a scheduled task in windows to invoke your console app once a day at the required time.
Add .Result at the end of schedFact.GetScheduler();
void Application_Start(object sender, EventArgs e)
{
ISchedulerFactory schedFact = new StdSchedulerFactory();
// get a scheduler
IScheduler sched = schedFact.GetScheduler().Result;
sched.Start();
// construct job info
JobDetail jobDetail = new JobDetail("mySendMailJob", typeof(SendMailJob));
// fire every`enter code here` day at 06:00
Trigger trigger = TriggerUtils.MakeDailyTrigger(06, 00);
trigger.Name = "mySendMailTrigger";
// schedule the job for execution
sched.ScheduleJob(jobDetail, trigger);
}
In addition to the good answer M4N provided, you can take a look at the spring.net integration of the quartz.net lib which allows to call methods without the need to implement IJob.
i searching for Quartz . i do this for my job:
1:instal Quartz from visual console:
PM> Install-Package quartz
2:create a class like this:
using Quartz;
public class Quartz : IJob
{
public void Execute(IJobExecutionContext context)
{
//do some
}
}
3.in global
using Quartz;
using Quartz.Impl;
protected void Application_Start(object sender, EventArgs e)
{
//for start time at first run after 1 hour
DateTimeOffset startTime = DateBuilder.FutureDate(1, IntervalUnit.Hour);
IJobDetail job = JobBuilder.Create<Quartz>()
.WithIdentity("job1")
.Build();
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity("trigger1")
.StartAt(startTime)
.WithSimpleSchedule(x => x.WithIntervalInSeconds(10).WithRepeatCount(2))
.Build();
ISchedulerFactory sf = new StdSchedulerFactory();
IScheduler sc = sf.GetScheduler();
sc.ScheduleJob(job, trigger);
sc.Start();
}
it is code that doing some job in every 10second for 3time.
good luck

Categories