ASP .NET - Quartz Scheduler only Executes jobs on user visit - c#

I need my emails to be sent automatically from my .NET application. However, when scheduling jobs for the future, the jobs are only executing when a user visits the site.
Global.asax.cs
void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
JobScheduler.Start();
}
Job Scheduler (ScheduledTasks.cs)
public class EmailJob : IJob
{
public void Execute(IJobExecutionContext context)
{
BDL.Utilities.sendEmailNotification(to, subject, body);
}
}
public static void start()
{
foreach (AspNetUser user in users)
{
IJobDetail job = JobBuilder.Create<EmailJob>().WithIdentity((jobidentity))
.UsingJobData("to", user.Email)
.UsingJobData("subject", subject)
.UsingJobData("body", bodyholder).Build();
ITrigger trigger = TriggerBuilder.Create()
// schedule for 1 day in the future
.StartAt(expdate.AddDays(1)))
.WithIdentity(triggerid)
.Build();
scheduler.ScheduleJob(job, trigger);
}
}
I have scheduled a trigger for 1 day in the future. This trigger should cause my job to execute 1 day in the future. However, for some reason this job will only execute if a user visits my site on the day the job is scheduled to fire. How can I make these Jobs be executed automatically by Quartz???
EDIT: My goal is to accomplish this without messing with the Application Pool threads. The accepted answer shows that this question is about merely replacing the user interaction with automated scripts. Whereas the duplicate asks for a way to maintain the application pool threads, and in Java I might add!

+1 to #BRAHIMKamel. You could consider using Hangfire to do some job processing in your ASP.NET application.
Be aware though, that as long as you rely on IIS application pool, your job could be terminated and restarted at any time. That means that your job code must tolerate multiple subsequent executions. Regarding e-mails that means that you should check whether you've already sent what you want before attempting to actually send message.

I was able to come up with a more elegant solution. Using the tool Zapix I was able to schedule my website to be quality checked every 20 minutes. Zapix simply visited the site and received and http response. By using Zapix, it mimicked the functionality of manually visiting the website to trigger the emails.

Related

Are Azure Web Jobs capable of keeping the task running in background?

I am currently experiencing difficulties with running a long HTTP request in a Web Job. Same application runs fine when started on local machine. Since I've tried multiple ways of trying to make this work I am now curious if this is possible at all.
My testing code below:
static void Main(string[] args)
{
/// [...]Getting configuration and using it in "SendPayload"
_stopwatch = new Stopwatch();
_stopwatch.Start();
Task.Run(async () => { await SendPayloadAndAwait(configuration); });
while (_isWaiting)
{
if (_stopwatch.ElapsedMilliseconds % 5000 == 0)
{
Console.WriteLine(".");
}
}
}
public static async Task<string> SendPayloadAndAwait (RequestModel targetRequest)
{
/// [...]Preparing client and payload
Console.WriteLine("Start");
Response= curClient.SendAsync(req).Result;
var endContent = Response.Content.ReadAsStringAsync().Result;
Console.WriteLine("End");
_isWaiting = false;
return "Done";
}
The "End" is never printed in Web Job console, it is an infinite (up to the point of timeout) loop of ".". Is such scenario somehow prohibited?
The way I solved at a previous company was by having the long running job in a Web API which was implemented as an Azure Function was
First call (i.e. /api/StartJob)
creates a job entry (in azure table)
starts backgound thread
returns a 202 [Accepted] status with the job entries Id
Background thread performs long running task updating job entry with it's progress
Client Loop (while percentage done < 100)
Requests status (i.e. /api/JobStatus)
If percentage done = 100 exit loop
This was very successful and reliable providing we had a paid for plan
The free plans kill the session after approx 5 minutes (by design)
You will need to enable the "Always on" setting to make sure your long-running job doesn't get terminated.
The web app times out after 20 minutes of inactivity, and only the requests to the actual web app resets this timer. The web jobs are executed asynchronously in a separate process, so they don't keep the web app "awake".
Here's a note from the web jobs documentation:
A web app can time out after 20 minutes of inactivity. and only requests to the actual web app can reset the timer. Viewing the app's configuration in the Azure portal or making requests to the advanced tools site (https://<app_name>.scm.azurewebsites.net) doesn't reset the timer. If you set your web app to run continuous or scheduled (timer-trigger) WebJobs, enable the Always on setting on your web app's Azure Configuration page to ensure that the WebJobs run reliably. This feature is available only in the Basic, Standard, and Premium pricing tiers.

Automatic run function for ever c# Quartz.net

I use Quartz.net in website for run job forever, and i want run job Automatically in server in every 15 min.
My problem is, User must visit site until application start in global.asax run and it works when user is in site, I want run job without visiting site and start it for ever without users be in site
I am using this code for running job in global.asax
void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup
SchedulerDemo.Interfaces.ISchedule myTask = new SchedulerDemo.Jobs.HelloSchedule();
myTask.Run();
}
By default in Quartz.net, the jobs list and their trigger will be stored in memory, so as you have suspected, it will have to be defined in the Application_Start to be called on the first request.
You first need to get and start the scheduler in itself.
IScheduler scheduler = StdSchedulerFactory.GetDefaultScheduler();
scheduler.Start();
Then, still in your Application_Start method, you will have to define the job and it's trigger :
// Instantiating the job
IJobDetail jobDetail = JobBuilder.Create<MyJob>()
.WithIdentity(new JobKey("MyVeryImportantJob", "VeryImportantJobGroup"))
.Build();
ITrigger jobTrigger = TriggerBuilder.Create()
.WithIdentity(new TriggerKey("MyVeryImportantJobTrigger", "VeryImportantJobTriggerGroup"))
.WithCronSchedule("* 0/15 * * * ?"") // execute every 15 min (in reality at HH:00, HH:15, HH:30 and HH:45)
.Build();
And join the two to schedule the job
scheduler.ScheduleJob(jobDetail, jobTrigger);
The scheduler will then manage to call your job according to the trigger you defined (in this case, every 15 min).
Also, as Quartz.Net will spawn a dedicated thread for the scheduler, it won't impact iis response process and it will prevent the iis worker to be recycled, so once it's launched, it will run forever until either the iis website or the host server is restarted.
After that, if you REALLY want your scheduler to start with the website without any request at all, you can use the Service Auto Start Provider (more info here :
https://www.simple-talk.com/blogs/2013/03/05/speeding-up-your-application-with-the-iis-auto-start-feature/
)

Birthdays Reminder Code for Asp.Net MVC

I want to create a web application in MVC Asp.Net for Hotel Room Booking and Customers Management. I am having trouble with one of the requirement. I want to create a code for Sending SMS to Customers on their Birthdays for Wishing them from Hotel. I am confused, that where should i place the code for checking customers with birthdate same as today's Date, so that Code gets Triggered every day at 12:00 am even if the web application is not launched. Please can you explain where should i insert the code?
There is a open-source library called Quarz which will help you with that.
There is a very good blog article by Mike Brind about this library. The library provides a fluent API which allows you to do exactly what you want.
The following code (based on the example of the mentioned blog article) creates a event which is called every day at 12 o´clock:
IScheduler scheduler = StdSchedulerFactory.GetDefaultScheduler();
scheduler.Start();
IJobDetail job = JobBuilder.Create<BirthdayJob>().Build();
ITrigger trigger = TriggerBuilder.Create()
.WithDailyTimeIntervalSchedule
(s =>
s.WithIntervalInHours(24)
.OnEveryDay()
.StartingDailyAt(TimeOfDay.HourAndMinuteOfDay(12, 0))
)
.Build();
scheduler.ScheduleJob(job, trigger);
It can run in the context of the Website, a Windows Service or even a WinForms-Application (as long the user doesn't closes it).
Depending on the context you need to schedule the job in different places. For a Website in would be the Application_Start()-Method. For a Service this would be the OnStart()-Method.
Additionally you need a class "BirthdayJob" which will provide the actual code which should be executed periodically:
public class BirthdayJob : IJob
{
public void Execute(IJobExecutionContext context)
{
// Check for birthdays...
}
}
There is one point you should be aware of if you call this code in the context of a website:
It's possible that the IIS puts your website to sleep if it isn't requested for a while. In this case it would be possible that the scheduled tasks are not executed.
There is an option to change the timeout for your website:
In the IIS manager go to "Application Pools", find the application pool that is used for your website and select "Properties" -> "Performance". There you can set the idle timeout. There are several other approaches to solve this problem.
However, if your website is requested frequently you would never see this problem.
The best way to go would be to call Quarz from a Windows-Service which runs even if your websites sleeps or lays down drunken under a table.
You could ship a service together with your web application which does the periodic checks and runs separately from the site.
Another usage of this service could be general maintenance of the data store which is used by the site, thus, for instance, once a day it would archive information, check birthdays and any other maintenance or periodic tasks, such as the issuing of reminders, etc. which your platform would issue.

how to create cron job in asp.net(v4.0) to run method every 30mins

I need some guidance on creating and running a Cron Job in asp.net(C#.net) to run every 30 minutes.i have created a class in that i have written code for getting tweets, facebook feeds.
i have created another page in that i have one button to download tweets and save in database.
If i want to get tweets i have to click on sync button every time.
i want to create cron job so that the database will get automatically synchronized with new tweets,facebook feeds.
Thanks
You can follow any one of the following approaches
Create a console app with the logic to fetch the tweets and feeds, and use a Task scheduler to run it for every 30 mins.
You could build a windows service, which polls the feeds within a timer and updates the db.
You could checkout this scheduler which is a rough equivalent to cron jobs. Personally haven't tried it. Check out this SO
If your intended 30-minute scheduled task is meant to be a discrete transactional action (like, for instance, your example of synchronizing some database values), then you may want to take a look at the Revalee open source project.
You can use it to schedule web callbacks at specific times. In your case, you could schedule a web callback (30 minutes in the future). When your ASP.NET application receives the callback, it can schedule the next 30 minute callback as well as perform whatever tasks you need it to handle every half-hour. When your ASP.NET application launches for the very first time, then you would schedule the first web callback. Since your web application is being called back, you do not need to worry about your web application unloading (which it will do periodically on IIS, for example).
For example using Revalee, you might do the following:
Register a future (30 minutes from now) callback when your application launches via the ScheduleThirtyMinuteCallback() method (see below).
private DateTimeOffet? previousCallbackTime = null;
private void ScheduleThirtyMinuteCallback()
{
// Schedule your callback 30 minutes from now
DateTimeOffset callbackTime = DateTimeOffset.Now.AddMinutes(30.0);
// Your web service's Uri, including any query string parameters your app might need
Uri callbackUrl = new Uri("http://yourwebapp.com/Callback.aspx");
// Register the callback request with the Revalee service
RevaleeRegistrar.ScheduleCallback(callbackTime, callbackUrl);
previousCallbackTime = callbackTime;
}
When the web scheduled task activates and calls your application back, you perform whatever action you need to do every 30 minutes and you schedule the next callback too. You do this by adding the following method call (CallbackMonitor()) to your Callback.aspx page handler.
private void CallbackMonitor()
{
if (!previousCallbackTime.HasValue
|| previousCallbackTime.Value <= DateTimeOffset.Now.AddMinutes(-30.0))
{
// Perform your "30 minutes have elapsed"-related tasks
// ...do your work here...
// Schedule subsequent 30 minute callback
ScheduleThirtyMinuteCallback();
}
}
To be clear, the Revalee Service is not an external 3rd party online scheduler service, but instead a Windows Service that you install and fully control on your own network. It resides and runs on a server of your own choosing, most likely your web server (but this is not a requirement), where it can receive callback registration requests from your ASP.NET application.
If, however, your 'run every 30 minutes' task is a long running task, then you probably do not want to embed that functionality within your ASP.NET application.
I hope this helps.
Disclaimer: I was one of the developers involved with the Revalee project. To be clear, however, Revalee is free, open source software. The source code is available on GitHub.

How to run long-lasting process asynchronously under asp.net?

.net 4.5, asp.net mvc: What is the best way to run long-lasting process (1-2 minutes) from ASP.NET application giving it should be run in a single-threaded environment, I mean the process is initiated for one user at a time only, executions for all other users have to wait till the current execution is done? The scenario is the following: user clicks button that run some sort of long-lasting calculations, http response returned to the user immediately, then user has to request status of the calculations with separate request manually. Asp.net http session abortion should not lead to the process termination, it should keep going. The process might be run on the same or separate server.
I'll show you how to perform this task with http://hangfire.io – incredibly easy way to perform fire-and-forget, delayed and recurring tasks inside ASP.NET applications. No Windows Service required.
First, install the package through NuGet. If you have any problems, please see the Quick Start guide in the official documentation.
PM> Install-Package Hangfire
Open your OWIN Startup class and add the following lines:
public void Configure(IAppBuilder app)
{
GlobalConfiguration.Configuration.UseSqlServerStorage("connection_string");
app.UseHangfireDashboard();
app.UseHangfireServer();
}
Then write the method that will do the long-running work (I applied attribute to perform only one method at a time):
[DisableConcurrentExecution]
public void LongRunning()
{
// Some processing stuff
}
And then call a method in background as fire-and-forget to respond user immediately:
public ActionResult Perform()
{
BackgroundJob.Enqueue(() => LongRunning());
return View();
}
If you want to notify a user about job completion, consider using SignalR and append the LongRunning method correspondingly.
.Net 4.5.2 adds QueueBackgroundWorkItem that you can use to schedule a task. If you don't control the server (when it's rebooted), the 90 second default delay of appPool shut down won't work (unless you can detect the task didn't complete and run it on another server). For more details see "QueueBackgroundWorkItem to reliably schedule and run background processes in ASP.NET"
I would suggest using a product such as NServiceBus to offload the processing and run it in single threaded mode. The advantage to this is that all requests will be processed in order and the processing can be offloaded from the web server as you don't really want long running processes to happen on a web server.
If you control the server, and need more simplicity that a full framework like Hangfire, you can make a console app (.exe), and make any thing..., then you can call the .exe with Process.Start Method, you can call the .exe from SQL Server to, service, etc.

Categories

Resources