I am developing an web app with ASP.NET MVC3.
The requirement is: At some time interval (0:00AM or 10:00pm), the app must automatically do some task such as: Change order status in DB, send notify email to customer, clear temp folder....
I'm thinking of using a thread in Global.aspx, let it run and sleep for 24 hours, but I don't think that is a good resolution.
#Thank to patryk-wiek comment, I find a solution with " Task Scheduler MVC" keywork here.
https://github.com/jgeurts/FluentScheduler
Is that a good solution or not? I think writing a window service is a bit overkill for me?
Don't do it in your web application as you may not be in control of when the host process times out and goes!
Create a windows service to perform these tasks.
http://msdn.microsoft.com/en-us/library/d56de412.aspx
you can use RX for the same by creating a window service for the same.. as i have attached one sample code below which would suscibe first and will do the operation in regular interval of 2 minutes.:-
Observable.Generate(
true,
_ => true,
i =>
{
////your code...
return i;
},
i => i,
_ => TimeSpan.FromMinutes(2)).Subscribe();
Don't do it inside your web app, becasue the AppPool can be terminated at any time. There are ways how to prevent this, but it's not very clean solution.
Use windows scheduler, WCF service or some workflow solution for log running tasks.
Related
I want to start below potentially long running thread in it's own AppDomain to prevent the webserver from aborting it during recycling. It compiles fine, however during runtime I get this cryptic error
Type is not resolved for member 'MyCore.MyWebService,MyCore,
Version=5.0.0.0, Culture=neutral, PublicKeyToken=null'.
How do I find out what member is not resolved?
Are there any better ways running a long standing thread in a MVC business service layer, that does not get aborted by the server recycling mechanism?
Here is the code:
namespace MyCore
{
[Serializable]
public class MyWebService : IMyWebService
{
AppDomain domain = AppDomain.CreateDomain("Domain");
Thread.CurrentThread.Name = "MVCThread";
domain.SetData("lDatabaseID", lDatabaseID);
domain.DoCallBack(() =>
{
long lID = Convert.ToInt64(AppDomain.CurrentDomain.GetData("lDatabaseID"));
Thread thread = new Thread(
(() =>
{
PopulateTables(lID );
}));
thread.Name = "DomThread";
thread.Start();
});
}
}
IIS is heavily optimised to respond very quickly to hundreds of small simultaneous requests and just isn't the right tool for what you're attempting. You can try to work around that but in the long term you'll be better off building a tool that is designed for long-running tasks. You've then got a pre-packaged solution the next time this problem arises.
The basic idea is to create an external application that does your background processing with some way to pass tasks to it and get results back. I like using the database to communicate as most web applications that need baground processing already use a database. Add a 'tasks' table with {status, startedDateTime, finishedDateTime, parameters, etc}, then write an external application that will periodically look for a new task, complete it and update the database. Your web site can poll the database for status or your application could make an AJAX call to notify the web site when a job has completed (a small iframe in the web site header that shows waiting / completed tasks can be useful if someone will be waiting for the job to complete and is easy to do).
EDIT: Before you do the above review HangFire (which works inside IIS, as a Windows Service or as a console app). Same principles, but a pre-packaged solution. Note that I haven't implemented this yet but it looks good.
Although it's a bit of work to set up, handing this task off to a Windows Service is a good approach if you might have multiple tasks and need them responded to quickly. There are a lot of tutorials on the web that will help you create a Windows Service, such as http://www.codeproject.com/Articles/106742/Creating-a-simple-Windows-Service but you'll have to build a simple task executor on top of that so if that's the way you want to go I'd look for a pre-built task engine (I couldn't find one quickly but I'm probably using the wrong search phrase).
But that's overkill if turn-around time isn't important and a better approach for you might be to create a small console application that will be started every five minutes by task scheduler. It would connect to the database, execute any waiting tasks then shut down again. This is easier to debug and install than a Windows service and achieves the same goal of moving the task execution out of IIS.
Remember that you still have to detect and handle Windows shutdown so that you don't get half-finished orphaned jobs - at the very least just tag that task as aborted and exit cleanly.
Alright after having mucked with Hangfire, I finally got it to work in .Net 4.0 and MVC 3. Had to install Common.Logging.Core 2.2.0, since the NuGet installed the wrong version (3.3.0)
In my Initial controller I added the following
namespace Core.Controllers
{
...
public void Configuration(IAppBuilder app)
{
app.UseHangfire(config =>
{
config.UseSqlServerStorage(ConnectionString.GetTVConnectionString());
config.UseServer();
});
}
...
}
ConnectionString.GetTVConnectionString() gets the connection string from the config file.
Up top I added the following
[assembly: OwinStartup(typeof(Core.Controllers.BaseController))]
In the code that starts the background thread I added the following, passing in a long instead of the class and having the job load the POCO class from the db.
BackgroundJob.Enqueue(() => PopulateTables(lDatabaseID, JobCancellationToken.Null));
The Enqueue() function returns a job id, that later can be used to cancel the job if needed, through the BackgroundJob.Delete(jobid) function.
In the job method I then have this
while (idxMin < max)
{
try
{
cancellationToken.ThrowIfCancellationRequested();
....
}
catch (JobAbortedException jobEx)
{
....
}
}
It's important to use dependency injection, so my class had a parameter less constructor added that re-reads the connection string rather than have it passed in.
public MyWebService ()
: this(ConnectionString.GetTVConnectionString())
{
}
public MyWebService (string sConnStr)
{
msConnStr = sConnStr;
}
After that it seems to run pretty well. A number of tables are added to the database specified in the connection string. So far it seems like the jobs survive recycling on the webserver.
In my ASP MVC 5 app I have this database related operation that I've to perform once in month maybe and it takes about 30 - 60 minutes.
I start this action like this:
Repository dbForCategories = new Repository();
dbForCategories.Database.CommandTimeout = 60000;
var t = Task.Factory.StartNew(async delegate
{
var crs = new ProductCategoryRelationsSetter(dbForCategories, categoryService);
crs.AddProductsCategoriesRelations(oneLineTree);
}, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default);
After about 5 minutes of working in background Im getting logged out of application. I think that the app resets because some static variables Im using are reset.
In elmah i don't have any errors. I put my code in Try Catch block.
Only hope in you guys:)
As #David mentioned, it's probably best to go the Windows Service route:
Write the item to a database table
Let a Windows Service poll the table every month (or however often you need it to).
If it finds a new item in the queue, let the Windows Service perform the operation.
Why not do Background threads in ASP.NET?
The server may recycle Application pool at some point and will not know to wait for your Task on a separate thread. (Discussed in this SO question)
.NET 4.5.2 onward. You can fire and forget short tasks
For interest sake you can use HostingEnvironment.QueueBackgroundWorkItem (see here) and the server will respect the background item and not recyle the App pool while it's busy, BUT ONLY for up to 90 seconds. anything longer and Windows Service is your best bet.
HostingEnvironment.QueueBackgroundWorkItem(ct => yourAsyncWork(ct));
Hangfire is wonderful for stuff like this.
https://www.nuget.org/packages/Hangfire/
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.
.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.
I would like to run a time consuming script (to update a database from a 3rd party API) at regular intervals. I was wondering what the best practice for this would be:
What should the 'script' be - an ASP.NET service? Bearing in mind I am on shared hosting, this may not be possible (but I would like to know).
How could the script be scheduled to run at regular intervals/at set time automatically?
Thanks in advance!
Some options for this:
Use a separate thread that keeps running all the time - and does the update on time (and then sleeps).
Use a timer and trigger the update event.
Use a Cache expiration trigger, but test this so that it keeps running without users visiting the site.
I would suggest checking out http://www.beansoftware.com/ASP.NET-Tutorials/Scheduled-Tasks.aspx for more details on these methods.
There is no way you can guarantee that something runs e.g. every night in a normal IIS setup. Batch jobs are thus a pain to handle. The only "mode" of execution for IIS is requests. If your application has no requests it doesn't run at all so IIS does not spend any resources on executing code in your application, i.e. it can unload it entirely.
If you have your own host, you would typically create a windows service to run your background tasks. I believe the same is possible in Azure. But for a standard sharesd IIS host, you basically can't setup a scheduled background task.
One of the simplest hacks is to setup a protected service that executes the job when it gets a request. Then you can make sure an external caller calls into your service at the required intervals.
What you can do is add a System.Timers.Timer in Global.asax.
System.Threading.Timer timer = new System.Threading.Timer(new TimerCallback(TimerElapsed), null, new Timespan(0), new Timespan(24, 0, 0));
// This will run every 24 hours.
private void TimerElapsed(object o)
{
// Do stuff.
}
In IISManager, enable HTTP-Keep Alives for your application.
In IIS Manager, select Http Response Headers Module, open it and in the Actions Pane, select Set Common Headers and in there select Enable Http Keep Alives.
Also, check for a setting of your application pool -
Select the application pool of your application, select Advanced Settings from the right Actions Tab.
In there there is a setting called - Idle Timeout (minutes)
By default it is 20 Minutes. Make it something like 60 Minutes or increase it even more and check.