I am working on a window service and I have to schedule it. Schedule is set to any three days of a week and four times a day. At any time when one starts service, It must pick the next execution time.
This next execution time can be in the same day or next scheduled day(may be with the gap of a day or two).
Take a look at Task Scheduler Managed Library (Codeplex). I believe it is maintained by Microsoft themselves.
Once you add the DLL reference to Microsoft.Win32.TaskScheduler, you can use it really easily like so:
var taskService = new TaskService();
var task = taskService.NewTask();
task.Triggers.Add(new WeeklyTrigger(DaysOfTheWeek.Friday, 1));
task.Actions.Add(new ExecAction("YourProgram.exe", null, null));
task.RootFolder.RegisterTaskDefinition("YourTaskName", task);
That will register a task that runs every Friday, executing YourProgram.exe.
Related
Basically what I have to do is create a thread that executes in a given number of days, which can change. The point is that an email should be sent periodically, and I'm looking for the best approach eventhough I know this is definitely not one of the best solutions but I must continue with this per requirements, hence I cannot use Windows Services, Windows Scheduler or anything similar. So the starting day for this email to be sent is when app starts, and then the next time should be after X days as specified in web.config. The problem is that I don't know how to keep track of that if the application stops (I can save the date of application start in database) but the number of days for the next execution may change. This is what I've done so far:
private async Task<int> EmailScheduler()
{
var day = DateTime.Now.Day; //day when app starts
while (true)
{
var currentTime = DateTime.Now;
if (currentTime.Day == day)
{
SendEmail("mailto", "", "", "subject", EmailMessage());
day += Int32.Parse(ConfigurationManager.AppSettings["NumberOfDays"]); //next schedule
}
await Task.Delay((int)TimeSpan.FromDays(1).TotalMilliseconds);
}
}
Thanks in advance.
You have no control over when your application pool restarts, and it will most certainly not be running for extended periods of time.
You could save the last execution date in a database, and periodically poll it to see if it has been longer than your given number of days.
The polling frequency would depend on your requirements.
This would somewhat approach sending a mail "every few days", but it would probably not be as accurate as a scheduled task.
I've searched a way to run a Background Task daily at a specific time, e.x. at at 12:00.
I've registered the BackgroundTask with a TimeTrigger, which unfortunately starts immediately after registering.
builder.SetTrigger(new TimeTrigger(24 * 60, false));
Is there a easier way, then checking every hour, if this is the right time of day?
Microsoft seems to avoid apps from triggering at a precise time, but you might be able to get close by calculating the number of minutes from the time the user registers the task to 12:00, then resubscribe another task from there set for 24*60 as you have. I'm unsure if Microsoft allows this within a Background task, but it's worth a shot.
Example of calculating the minutes to midnight for the task
var tommorowMidnight = DateTime.Today.AddDays(1);
var timeTilMidnight = tommorowMidnight - DateTime.Now;
var minutesTilMidnight = (uint)timeTilMidnight.TotalMinutes;
builder.SetTrigger(new TimeTrigger(minutesTilMidnight, true));
I've used this task wrapper to create something like this before and it fired everyday. Maybe this is what you are looking for.
http://taskscheduler.codeplex.com/
I am using quartz.net with CRON scheduling.
I set misfire instruction to : fire and proceed:
trigger = Quartz.TriggerBuilder.Create()
.WithIdentity(jobData.JobId, jobData.ClientApplicationId.ToString())//.WithCronSchedule(scheduleInfo.CronExpression, WithMisfireHandlingInstructionDoNothing())
.WithSchedule(Quartz.CronScheduleBuilder.CronSchedule(new Quartz.CronExpression(scheduleInfo.CronExpression)).WithMisfireHandlingInstructionFireAndProceed())//.WithMisfireHandlingInstructionDoNothing()) ///.WithMisfireHandlingInstructionFireAndProceed()
.StartAt(DateTime.Now).ForJob(iJobDetail)
.Build();
From what I read, if a trigger was missed , it should fire as soon as the scheduler is up
(one time maximum, even if the job was suppose to run many times).
For some reason when I test it, the job is never triggered.
Say I have a job that should run every hour starting from 4:00.
I turn on the scheduler at 7:30 , I don't get any trigger fires - until 8:00.
misfireThreshold is set to (60000) - one minute.
The job is statefuul and does not allow concurrent runs.
I am using a persistent store (AdoJobStore) -saving the schedules to the MSSQL DB.
Any idea why the trigger isn't firing on schedule activation?
Try the code below instead. Make sure to replace {YourCronExpressionString} with your own cron expression.
trigger = Quartz.TriggerBuilder.Create()
.WithIdentity(jobData.JobId, jobData.ClientApplicationId.ToString())
.WithCronSchedule("{YourCronExpressionString}", x => x.WithMisfireHandlingInstructionFireAndProceed())
.StartAt(DateTime.Now).ForJob(iJobDetail)
.Build();
Source: Quartz.NET setting MisfireInstruction
try to use PauseJob(jobKey) method to missfire
use ResumeJob(jobKey) method to trigger it again
for example:
set cronexpression:every 4 hours
at 7:30 , call pauseJob method
and at 8:01,call resumeJob method
the job at 8:00 will be refire
I have written a little program that creates a scheduled task. I wanted this task to run every day at any time between 6pm and 11.59pm. For this reason, I created this trigger
td.Triggers.Add(new DailyTrigger
{
DaysInterval = 1,
StartBoundary = DateTime.Today + TimeSpan.FromHours(18),
RandomDelay = TimeSpan.FromMinutes(359)
});
Problem is that in the Task Scheduler window the task that I create always is set to run at 6
What am I doing wrong?
This is the correct syntax to achieve your results. Unfortunately, the Task Scheduler app in Windows does not display information about delays. (BTW, I'm the author of that library and am 100% confident that your task will execute as you desire.) For detail on the functionality of the RandomDelay property see the Microsoft documentation.
Here I below pasted code I'm using in current window service solution, this will run job every day 10 AM regularly, I will pass the parameters using App.configuaration file
APP.CONFIG
<add key ="FIREHOST_TIME" value ="10" ></add>
<add key ="SETDAYS" value ="1" ></add>
CODE BEHIND PAGE
protected override void OnStart(string[] args)
{
DateTime tenAM = DateTime.Today.AddHours(FIREHOST_TIME);
if (DateTime.Now > tenAM)
tenAM = tenAM.AddDays(SETDAYS);
// calculate milliseconds until the next 10:00 AM.
int timeToFirstExecution = (int)tenAM.Subtract(DateTime.Now).TotalMilliseconds;
// calculate the number of milliseconds in 24 hours.
int timeBetweenCalls = (int)new TimeSpan(24, 0, 0).TotalMilliseconds;
TimerCallback methodToExecute = kickstart;
// start the timer. The timer will execute "ProcessFile" when the number of seconds between now and
// the next 10:00 AM elapse. After that, it will execute every 24 hours.
System.Threading.Timer timer = new System.Threading.Timer(methodToExecute, null, timeToFirstExecution, timeBetweenCalls);
}
Now I am trying to run my service, based up on the below Mentioned conditions:
I want to start my service but it should job perform the job based on the this new tag which I will add newly in app.config
BY based on above four tags
if RUN_NOW == 1
has to perform service based on FIREHOST_TIME and SETDAYS normal thing
else
service have to perform the Job doing by after 5 days(because WAIT_DAYS = 5)
then it have to use the FIREHOST_TIME and SETDAYS value
Note: service should not get stopped, it should be in started condition only
How can I achieve this?
I don't know exactly how you want implement the whole program logic, the portion I can try to help you is about reacting to a config file modification without restarting the service, this can be done with:
ConfigurationManager.RefreshSection("thesectiontorefresh");
for a better work, you can call this with a FileSystemWatcher listening for someone modifying the app.config file and react properly after calling the refresh as show above. You can obtain the configuration file path with this:
AppDomain.CurrentDomain.SetupInformation.ConfigurationFile
As a general information, consider to redesign the way you are solving the problem by using system scheduled task instead of writing your own service.