I'm developing a rather large website with which included a customer base and billing plans. The monthly billing should happen automatically (however, an employee should, manually, click a button to initiate the process every month due to business rules) and the number of customers are between 3000 - 5000. On every single invoice, the price lines should be calculated based on quite a lot of parameters and even external data from a webservice.
The above will definitely be a (very) long running task and since the application is an ASP.NET MVC website running on IIS, I don't want the process to run in it's own thread on IIS. My concerns are that if anything happens to IIS/the webserver, the billing calculation process stops aswell, which would be critical, to say the least.
Therefore I'm looking for alternatives and have read about creating a Windows Service for tasks like this. Is this the way to go? Or is there other, maybe more "modern" ways of running long processes? The process has to able to be started from the ASP.NET MVC application though.
Any help/hint is greatly appreciated! :-)
I actually had a requirement a few years back to do something similar to this. It was for processing monthly membership dues. The way I would do it is simple. First, in your database, add a table similar to this:
Of course, you can add other fields as you see fit. This is only for a demonstration.
Next, create your web page that contains the button that should get pressed monthly to begin the processing. When the button gets hit, it should perform the following logic:
DateTime.Now
)ProcessMonth
equal toDateTime.Now.Month
ANDProcessYear
equal toDateTime.Now.Year
.HasBeenProcessed
istrue
andProcessDate
to see when and report this to the user and you are done. This is an important step because if rows are returns andHasBeenProcessed
istrue
, then the monthly dues have probably already run for this month and you do not want to double charge people. So don't skip this step and stop the program execution logic here ifHasBeenProcessed
is true!ProcessMonth
equal toDateTime.Now.Month
,ProcessYear
toDateTime.Now.Year
. SetCanBeProcessed
totrue
andHasBeenProcessed
tofalse
.The last piece of the puzzle is to have a Windows Service that sits in the background and periodically pulls all rows from the database where
HasBeenProcessed
is equal tofalse
ANDCanBeProcessed
is equal totrue
.If any rows are returned, then you just process them and after processing them, set the
ProcessDate
toDateTime.Now
and setHasBeenProcessed
totrue
. Finally, your service just goes back to periodically checking. When I say "periodically checking", I'm talking about maybe once a day or maybe even once a week, depending on your requirements. This service shouldn't bog down your SQL server in any way.Instead of a Windows Service, you could have a Console Application that is scheduled to run with Windows Scheduler. I prefer the Windows Service way though, because it just "feels more right" to me.
Now if you wanted to get really fancy about it, you could write your schedule time and logic in an interface. This way you could reuse this Windows Service down the road.