Thread that executes every X number of days on c# - ASP.NET - c#

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.

Related

Run Background Task at specific time - Windows 10 App

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/

C#: get next execution time of window service

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.

work the service based upon datetime parameteric caluclations by using c# window service

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.

ASP.NET: Firing batch jobs

My application could have up to roughly 100 requests for a batch job within a few milliseconds but in actuality, these job requests are being masked as one job request.
To fix this issue so that only one job request is just not feasible at the moment.
A workaround that I have thought is to program my application to fulfill only 1 batch job every x milliseconds, in this case I was thinking of 200 milliseconds, and ignore any other batch job that may come in within those 200 milliseconds or when my batch job have completed. After those 200 milliseconds are up or when the batch job is completed, my application will wait and accept 1 job request from that time on and it will not process any requests that may have been ignored before. Once my application accepts another job requests, it will repeat the cycle above.
What's the best way of doing this using .Net 4.0? Are there any boiler plate code that I can simply follow as a guide?
Update
Sorry for being unclear. I have added more details about my scenario. Also I just realized that my proposed workaround above will not work. Sorry guys, lol. Here's some background information.
I have an application that builds an index using files in a specified directory. When a file is added, deleted or modified in this directory, my application listens for these events using a FileSystemWatcher and re-indexes these files. The problem is that around 100 files can be added, deleted or modified by an external process and they occur very quickly, ie: within a few milliseconds. My end goal is to re-index these files after the last file change have occurred by the external process. The best solution is to modify the external process to signal my application when it has finished modifying the files I'm listening to but that's not feasible at the moment. Thus, I have to create a workaround.
A workaround that may solve my problem is to wait for the first file change. When the first file change have occurred, wait 200 milliseconds for any other subsequent file changes. Why 200 milliseconds? Because I'm hoping and confident that the external process can perform its file changes within 200 milliseconds. Once my application have waited for 200 milliseconds, I would like it to start a task that will re-index the files and go through another cycle of listening to a file change.
What's the best way of doing this?
Again, sorry for the confusion.
This question is a bit too high level to guess at.
My guess is your application is run as a service, you have your requests come into your application and arrive in a queue to be processed. And every 200 ms, you wake the queue and pop and item off for processing.
I'm confused about the "masked as one job request". Since you mentioned you will "ignore any other batch job", my guess is you haven't arranged your code to accept the incoming requests in a queue.
Regardless, you will generally always have one application process running (your service) and if you choose you could spawn a new thread for each item you process in the queue. You can monitor how much cpu/memory utilization this required and adjust the firing time (200ms) accordingly.
I may not be accurately understanding the problem, but my recommendation is to use the singleton pattern to work around this issue.
With the singleton approach, you can implement a lock on an object (the access method could potentially be something along the lines of BatchProcessor::GetBatchResults) that would then lock all requests to the batch job results object. Once the batch has finished, the lock will be released, and the underlying object, will have the results of the batch job available.
Please keep in mind that this is a "work around". There may be a better solution that involves looking into and changing the underlying business logic that causes multiple requests to come in for a job that's processing on demand.
Update:
Here is a link for information regarding Singleton (includes code examples): http://msdn.microsoft.com/en-us/library/ff650316.aspx
It is my understanding that the poster has some sort of an application that sits and waits for incoming requests to perform a batch job. The problem that he is receiving multiple requests within a short period of time that should actually have come in as just a single request. And, unfortunately, he is not able to solve this problem.
So, his solution is to assume that all requests received within a 200 ms timespan are the same, and to only process these once. My concern with this would be whether this assumption is correct or not? This entirely depends on the sending systems and the environment in which this is being used. The general idea to be able to do this would be to update a lastReceived date/time when a request is processed. Then when a new request comes in, compare the current date/time to the lastReceived date/time and only process it if the difference is greater than 200 ms.
Other possible solutions:
You said you could not modify the sending application so only one job request was sent, but could you add additional information to it, for instance a unique identifier?
Could you store the parameters from the last job request and compare it with the next job request and only process them if they are different?
Based on your Update
Here is an example how you could wait 200ms using a Timer:
static Timer timer;
static int waitTime = 200; //in ms
static void Main(string[] args)
{
FileSystemWatcher fsw = new FileSystemWatcher();
fsw.Path = #"C:\temp\";
fsw.Created += new FileSystemEventHandler(fsw_Created);
fsw.EnableRaisingEvents = true;
Console.ReadLine();
}
static void fsw_Created(object sender, FileSystemEventArgs e)
{
DateTime currTime = DateTime.Now;
if (timer == null)
{
Console.WriteLine("Started # " + currTime);
timer = new Timer();
timer.Interval = waitTime;
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
timer.Start();
}
else
{
Console.WriteLine("Ignored # " + currTime);
}
}
static void timer_Elapsed(object sender, ElapsedEventArgs e)
{
//Start task here
Console.WriteLine("Elapsed # " + DateTime.Now);
timer = null;
}

C# regulate number of emails sent

I was wondering if anyone knows a good way to regulate how many emails are sent through C#?
Here is my scenario. I have a windows service that monitors three other windows services. I am using a service controller to get the status of all 3 services and if the status of any of these services change to stopped, it sends an email. My issue is, I run this on a 60 second timer so it sends an email every 60 seconds until someone starts the service back up.
My first thought was, when first email is sent, create a text file and use a counter to number it. Do this while counter < 6 so I will only receive 5 emails max. I think this will work but it seems kind of silly.
Does anyone have an alternative to this or should I just go with my first thought and perform clean up on the files?
Thank you
EDIT: The reason that I was trying to limit the number of emails sent is because the people who receive these emails do not react very quickly. At the same time, those who handle Exchange do not want the service to spam people. I felt 5 would be enough to appease both sides.
I would suggest that you should track the down time of each service.
So every 60 seconds you check, if a service is down, store the DateTime that the service is down. The on the next 60 second interval you can check to see if the service was already down. i.e. you can tell if the service just went down or has been down a while. You can also add another flag to determine if the the last check was UP or DOWN.
Then when the program first finds the service down it can send the email. Once the service is back up it can reset this flag values so the next down time it knows to send a new email.
You can then also use these flags to delay email frequency if desired. Just add a new DateTime field for LastEmailSentTime and compare that with whatever interval you want for error emails (say 10 minutes)
Hope that gives you some ideas
EDIT: Some Sample...
bool ServiceWasDown = false;
DateTime ServiceDownTime = DateTime.Now;
DateTime LastEmailTime = DateTime.Now;
void OnTimerElapsed()
{
if(IsServiceDown())
ServiceDown();
else
ServiceUp();
}
void ServiceDown()
{
if(ServiceWasDown)//already know about service
{
//if LastEmailTime more than 10 minutes ago send another email and update LastEmailTime
}
else//service just went down
{
//send new email
LastEmailTime = DateTime.Now;
ServiceWasDown = true;
ServiceDownTime = DateTime.Now;
}
}
void ServiceUp()
{
ServiceWasDown = false;
}
If you use a System.Timers.Timer then You can add a int variable for count Elapsed events.

Categories