238

Today we have built a console application for running the scheduled tasks for our ASP.NET website. But I think this approach is a bit error prone and difficult to maintain. How do you execute your scheduled task (in an windows/IIS/ASP.NET environment)

Update:

Examples of tasks:

  • Sending email from an email-queue in the database
  • Removing outdated objects from the database
  • Retrieving stats from Google AdWords and fill a table in the database.
ankita alung
  • 327
  • 3
  • 6
  • 20
Niels Bosma
  • 11,758
  • 29
  • 89
  • 148
  • What's an example of the tasks you're running? – JeffO Feb 12 '09 at 19:12
  • 4
    You need to check http://atrigger.com/ –  Aug 26 '13 at 11:15
  • If you have Plesk you can write a vbs and ad it to Task Scheduler: http://www.net24.co.nz/kb/article/AA-00213/13/Shared-Hosting/ASP-ASP.NET/Using-the-Plesk-Windows-Scheduler-to-call-an-ASP-or-.NET-page.html – HasanG Jun 10 '14 at 22:26

16 Answers16

130

This technique by Jeff Atwood for Stackoverflow is the simplest method I've come across. It relies on the "cache item removed" callback mechanism build into ASP.NET's cache system

Update: Stackoverflow has outgrown this method. It only works while the website is running but it's a very simple technique that is useful for many people.

Also check out Quartz.NET

Community
  • 1
  • 1
BC.
  • 24,298
  • 12
  • 47
  • 62
  • 12
    So what happens if the application isn't running, but the scheduled task needs to happen? – MichaelGG Feb 12 '09 at 19:16
  • 2
    This also could slow down the user experience if the task happens to take a while to run this time. I prefer not to have the user spawn my maintenance/tasks for me. – Brettski Feb 12 '09 at 19:21
  • 6
    This is scary as hell! Anything could cause the application to stop running and it'd probably only restart on the next user request. Between those times, your tasks don't run! – teedyay Feb 12 '09 at 19:41
  • Most of the objections are the result of confusion between a background task and service task. They are different things. – Joel Coehoorn Feb 12 '09 at 19:51
  • 2
    @Joel I agree. If you have service tasks that must run regardless of the state of the application, this is not the correct method. In other cases, I keep a generic service application template that helps me write services neatly and quickly. – BC. Feb 12 '09 at 20:15
  • blog.stackoverflow.com seems to be down, so the first link is currently dead. :( – John Rudy Feb 12 '09 at 21:08
  • 44
    Something I noticed today in the comments to the original blog post: `No, we’ve switched to a dedicated task. We definitely outgrew this technique. I do think it’s fine for small sites though!` -- Jeff Atwood – Joel Coehoorn Mar 02 '10 at 22:33
  • How does this work with multiple worker processes ? – Anthony May 21 '10 at 02:52
  • 3
    -1 Theres a big flaw with this approach. Whenever the application is recycled the 'CacheItemRemoved' event fires and your scheduled task will run. On production sites this can happen a few times a day. Not so good if you want the task to run weekly. – Steven de Salas Nov 05 '14 at 01:09
  • @StevendeSalas you're right, although in my defense, the answer mentions that it only works while the app is running and may not fit every use case. – BC. Nov 05 '14 at 19:39
  • @BC no problem there, just wanted to higlight this fact so other users are aware this approach is only useful for tasks being run reasonably frequently (every 10 minutes, hourly etc). – Steven de Salas Nov 06 '14 at 02:27
  • NOBODY mentioned that this can only be used on single server environment?? what about server farms?? c'mon.. – yakya Aug 31 '16 at 08:03
76

All of my tasks (which need to be scheduled) for a website are kept within the website and called from a special page. I then wrote a simple Windows service which calls this page every so often. Once the page runs it returns a value. If I know there is more work to be done, I run the page again, right away, otherwise I run it in a little while. This has worked really well for me and keeps all my task logic with the web code. Before writing the simple Windows service, I used Windows scheduler to call the page every x minutes.

Another convenient way to run this is to use a monitoring service like Pingdom. Point their http check to the page which runs your service code. Have the page return results which then can be used to trigger Pingdom to send alert messages when something isn't right.

Brettski
  • 19,351
  • 15
  • 74
  • 97
  • 3
    This is the solution I ended up with. Instead of a custom web service I use windows scheduler + curl. What's the benefity of using a windows service. – Niels Bosma Feb 23 '09 at 08:53
  • 2
    NO benefit, it's all in the way you put it together. Yours is a great solution. – Brettski Feb 23 '09 at 23:39
  • 16
    Have you looked at the Cache Item expiration technique? I think you will find that it is a much more ideal implementation of a scheduled service: http://www.codeproject.com/KB/aspnet/ASPNETService.aspx – Richard Clayton Aug 01 '09 at 05:24
  • 11
    What's to stop a malicious user (or a search engine spider) calling this page, and thus causing your scheduled tasks to run? – UpTheCreek Nov 03 '09 at 08:54
  • Nothing is, and does it really matter? This has never been an issue for me. You could easily write some logic around something not to run too often if its a heavy job. Not really sure how a spider will find the page? – Brettski Nov 03 '09 at 14:33
  • 9
    You can stop malicious calls by storing a static timestamp in the web app and only running if the timestamp has not been set (first call) or the correct time has expired since last call. – Rob Kent Nov 24 '11 at 17:37
  • 1
    The sad thing is I hit my asp.net pages using node.js as it was so darn easy to setup a service. I just used setTimeout and go through an array of URLs i want to hit. So easy it made me sick compared to doing it with cron or a windows service. – King Friday Feb 28 '13 at 18:17
  • @NielsBosma: you used windows scheduler + curl, could you please share your curl code since that seems to be exactly what I need :) Send me a PM or post it here if you like. Many thanks ahead! – Adam May 08 '13 at 08:03
  • 1
    Curl if very simple to use. For a simple get use curl http://mysite.com. Docs for more details are here: http://curl.haxx.se/docs – Brettski May 09 '13 at 12:52
  • Pingdom costs 11 EUR/ month WTF?? Thanks for not posting a dealer URL – Toolkit Apr 20 '16 at 08:39
  • 1
    I'm for a windows service, it is much more reliable and flexible over a windows scheduled tasks. Plenty of us realized the shortcomings and stability issues and lack of flexibility with windows scheduler. It is not worth it in the end. Unless you have done a lot of both, you might not realize how much better a windows service really is. – Tom Stickel Jun 14 '16 at 17:01
  • I can't disagree @TomStickel though if you are running on a shared host or somewhere else you don't have the option to install a windows service, it is still a good option. – Brettski Jun 17 '16 at 01:18
  • 6
    I stop malicious calls to my url by checking if the ip address is an internal address or not. It returns nothing and does nothing if it is not internal to our organization. – user1408767 Jul 12 '16 at 20:16
  • Malicious calls can be filtered out by checking for a secret key sent with the request. – Ian Warburton Mar 02 '20 at 16:43
  • 2
    @user1408767 the source IP can easily be spoofed. – Crisp Apples Mar 20 '20 at 16:35
  • I was looking for running scheduled task in dot net core webapi and found this article https://stacksecrets.com/dot-net-core/scheduled-repeating-task-with-net-core. It mentions use of IHostedService and Timer to achieve this. Is this a good way of doing this? – Hem Bhagat Apr 08 '22 at 09:54
  • I haven't used core. You should as a new question around this perhaps. – Brettski Apr 08 '22 at 21:10
32

Create a custom Windows Service.

I had some mission-critical tasks set up as scheduled console apps and found them difficult to maintain. I created a Windows Service with a 'heartbeat' that would check a schedule in my DB every couple of minutes. It's worked out really well.

Having said that, I still use scheduled console apps for most of my non-critical maintenance tasks. If it ain't broke, don't fix it.

Jacob
  • 3,598
  • 4
  • 35
  • 56
Chris Van Opstal
  • 36,423
  • 9
  • 73
  • 90
  • 7
    FYI the link is now dead. – Charles Burns Jan 21 '15 at 20:41
  • 2
    @CharlesBurns, you can always browse dead links with archive.org: https://web.archive.org/web/20090919131944/http://www.dotheweb.net/articles/dotnet/services.aspx – Nikolay Kostov Jan 02 '16 at 11:52
  • What is hard to maintain about the console apps and the windows service solve? We use the console scripts for all the tasks, but the scheduler is database engine job agent. We are thinking to build some web GUI around it and manage access permission on the application level (scheduler will became part of its own web application). – Muflix Mar 10 '21 at 10:00
17

I've found this to be easy for all involved:

  • Create a webservice method such as DoSuchAndSuchProcess
  • Create a console app that calls this webmethod.
  • Schedule the console app in the task scheduler.

Using this methodology all of the business logic is contained in your web app, but you have the reliability of the windows task manager, or any other commercial task manager to kick it off and record any return information such as an execution report. Using a web service instead of posting to a page has a bit of an advantage because it's easier to get return data from a webservice.

Daniel Auger
  • 12,535
  • 5
  • 52
  • 73
10

Why reinvent the wheel, use the Threading and the Timer class.

    protected void Application_Start()
    {
        Thread thread = new Thread(new ThreadStart(ThreadFunc));
        thread.IsBackground = true;
        thread.Name = "ThreadFunc";
        thread.Start();
    }

    protected void ThreadFunc()
    {
        System.Timers.Timer t = new System.Timers.Timer();
        t.Elapsed += new System.Timers.ElapsedEventHandler(TimerWorker);
        t.Interval = 10000;
        t.Enabled = true;
        t.AutoReset = true;
        t.Start();
    }

    protected void TimerWorker(object sender, System.Timers.ElapsedEventArgs e)
    {
        //work args
    }
harriyott
  • 10,505
  • 10
  • 64
  • 103
  • 7
    You don't need to spawn a thread to start a timer... – Zyo May 17 '12 at 17:10
  • 4
    I too don't think it's an ideal solution. – Liron Harel Jul 30 '12 at 12:02
  • 12
    @IdanShechter it would be good to tell a reason why you consider this not an ideal solution – Omu Nov 23 '12 at 23:58
  • 2
    Thread could be problematic, because it is not HttpRequest, some data involving HttpRequest can be null. For Example HttpRequest .ApplicationPath. If the task is written properly, it will work. Another issue is application pool restarting. If the pool is restarting too often(memory leaks...), the worker will never run. – Tomas Kubes Jun 27 '13 at 20:56
  • 4
    In case you have several instances running (e.g. load balancing) - probably you wouldn't want this solution (several tasks doing the same) – Illidan Mar 11 '14 at 06:58
9

Use Windows Scheduler to run a web page.

To prevent malicous user or search engine spiders to run it, when you setup the scheduled task, simply call the web page with a querystring, ie : mypage.aspx?from=scheduledtask

Then in the page load, simply use a condition : if (Request.Querystring["from"] == "scheduledtask") { //executetask }

This way no search engine spider or malicious user will be able to execute your scheduled task.

philberg
  • 91
  • 1
  • 1
  • 6
    Better yet, use a salted hashing algorithm that actually verifies the querystring with a little more security than a magic phrase. The req would be something like like mypage.aspx?salt=foo&hash=1223523jbhdgu13t1. You just have to have the same hashing algorithm on both server and client. Also add a hard limit on the server; save when it was executed and prevent from executing too fast. I might be paranoid though. – Joel Peltonen Jul 31 '13 at 09:32
  • 15
    Even more secure, use Windows Scheduler to run a web page that checks if the request is coming from the server itself: `Request.IsLocal` >> only the server itself can run the scheduled tasks, no one else. – The Conspiracy Apr 18 '14 at 20:06
  • Do you have more experiences from your approach? I was going to develop similar type of service of our app and now I can't decide if it's better calling a page with scheduled task or cron, or if to use cache system. – JayDee Nov 14 '19 at 14:40
4

This library works like a charm http://www.codeproject.com/KB/cs/tsnewlib.aspx

It allows you to manage Windows scheduled tasks directly through your .NET code.

labilbe
  • 3,501
  • 2
  • 29
  • 34
3

Additionally, if your application uses SQL SERVER you can use the SQL Agent to schedule your tasks. This is where we commonly put re-occurring code that is data driven (email reminders, scheduled maintenance, purges, etc...). A great feature that is built in with the SQL Agent is failure notification options, which can alert you if a critical task fails.

Zachary
  • 6,522
  • 22
  • 34
2

I'm not sure what kind of scheduled tasks you mean. If you mean stuff like "every hour, refresh foo.xml" type tasks, then use the Windows Scheduled Tasks system. (The "at" command, or via the controller.) Have it either run a console app or request a special page that kicks off the process.

Edit: I should add, this is an OK way to get your IIS app running at scheduled points too. So suppose you want to check your DB every 30 minutes and email reminders to users about some data, you can use scheduled tasks to request this page and hence get IIS processing things.

If your needs are more complex, you might consider creating a Windows Service and having it run a loop to do whatever processing you need. This also has the benefit of separating out the code for scaling or management purposes. On the downside, you need to deal with Windows services.

MichaelGG
  • 9,976
  • 1
  • 39
  • 82
2

If you own the server you should use the windows task scheduler. Use AT /? from the command line to see the options.

Otherwise, from a web based environment, you might have to do something nasty like set up a different machine to make requests to a certain page on a timed interval.

t3rse
  • 10,024
  • 11
  • 57
  • 84
2

I've used Abidar successfully in an ASP.NET project (here's some background information).

The only problem with this method is that the tasks won't run if the ASP.NET web application is unloaded from memory (ie. due to low usage). One thing I tried is creating a task to hit the web application every 5 minutes, keeping it alive, but this didn't seem to work reliably, so now I'm using the Windows scheduler and basic console application to do this instead.

The ideal solution is creating a Windows service, though this might not be possible (ie. if you're using a shared hosting environment). It also makes things a little easier from a maintenance perspective to keep things within the web application.

Mun
  • 14,098
  • 11
  • 59
  • 83
1

Here's another way:

1) Create a "heartbeat" web script that is responsible for launching the tasks if they are DUE or overdue to be launched.

2) Create a scheduled process somewhere (preferrably on the same web server) that hits the webscript and forces it to run at a regular interval. (e.g. windows schedule task that quietly launches the heatbeat script using IE or whathaveyou)

The fact that the task code is contained within a web script is purely for the sake of keeping the code within the web application code-base (the assumption is that both are dependent on each other), which would be easier for web developers to manage.

The alternate approach is to create an executable server script / program that does all the schedule work itself and run the executable itself as a scheduled task. This can allow for fundamental decoupling between the web application and the scheduled task. Hence if you need your scheduled tasks to run even in the even that the web app / database might be down or inaccessible, you should go with this approach.

Matias Nino
  • 4,265
  • 13
  • 46
  • 63
1

You can easily create a Windows Service that runs code on interval using the 'ThreadPool.RegisterWaitForSingleObject' method. It is really slick and quite easy to get set up. This method is a more streamlined approach then to use any of the Timers in the Framework.

Have a look at the link below for more information:

Running a Periodic Process in .NET using a Windows Service:
http://allen-conway-dotnet.blogspot.com/2009/12/running-periodic-process-in-net-using.html

atconway
  • 20,624
  • 30
  • 159
  • 229
0

We use console applications also. If you use logging tools like Log4net you can properly monitor their execution. Also, I'm not sure how they are more difficult to maintain than a web page, given you may be sharing some of the same code libraries between the two if it is designed properly.

If you are against having those tasks run on a timed basis, you could have a web page in your administrative section of your website that acts as a queue. User puts in a request to run the task, it in turn inserts a blank datestamp record on MyProcessQueue table and your scheduled task is checking every X minutes for a new record in MyProcessQueue. That way, it only runs when the customer wants it to run.

Hope those suggestions help.

Kyle B.
  • 5,737
  • 6
  • 39
  • 57
0

One option would be to set up a windows service and get that to call your scheduled task.

In winforms I've used Timers put don't think this would work well in ASP.NET

AJM
  • 32,054
  • 48
  • 155
  • 243
-1

A New Task Scheduler Class Library for .NET

Note: Since this library was created, Microsoft has introduced a new task scheduler (Task Scheduler 2.0) for Windows Vista. This library is a wrapper for the Task Scheduler 1.0 interface, which is still available in Vista and is compatible with Windows XP, Windows Server 2003 and Windows 2000.

http://www.codeproject.com/KB/cs/tsnewlib.aspx

Ali
  • 1
  • 1