0

I've read a good bit about threading with C#, but to be upfront I haven't done anything in production using it.

I have an application that has to process a bunch of documents and then send the documents via email. This may take 60 seconds to accomplish. I don't want the user of my web application to have to wait for these things to process to move on to other parts of the site.

On a button click the SendEmail function is called. What can I do to this code to make it so that my users can continue browsing the site without discontinuing the processing I need to do within the EmailPDFs function?

    [Authorize]
    public ActionResult SendEmail(decimal? id, decimal? id2)
    {
       EmailPDFs(..., ..., ...);  
    }

Thanks so much!

J Hunt
  • 733
  • 1
  • 10
  • 21
  • 2
    I wouldn't do this in a web application, dump the job into a queue and have an external service pick up and process the job, for example. – Lloyd Jun 24 '15 at 15:55
  • but have a plan on how to communicate success/ failure to the user that created the command. – Mario The Spoon Jun 24 '15 at 15:59
  • Lloyd, what type of external service do you suggest? Thanks for the comment Lloyd and Mario. – J Hunt Jun 24 '15 at 16:20
  • What would be the harm in doing something like this? Task.Factory.StartNew(() => { EmailPDFs(..., ..., ...); }); – J Hunt Jun 24 '15 at 16:31
  • The harm is IIS can shut down your AppDomain before the task finishes. The AppDomain only remains alive while you have active visitors, if no one is visiting it does not take in to account running background threads before tearing down the domain (Think performing a "end task" on your program). See [this answer of mine](http://stackoverflow.com/questions/30419739/return-to-view-with-async-await/30419845#30419845) to another question for a example of how to ask IIS to give you up to 90 additional seconds to finish your background work before end tasking your task. – Scott Chamberlain Jun 24 '15 at 16:51

1 Answers1

2

This is really the kind of thing that message queues are designed to handle. Fire off a message, and a process on a potentially separate server picks it up and processes it. When it's done, it sends a message back to a queue on your server, where a process on your server picks it up and notifies you that it's complete. You then notify your user that the work is finished.

Modern message queue systems can be backed by databases (such as Mongo, MySql, or SQL Server), and are extremely robust. The great thing about them is that they allow you to move long-running or CPU-intensive processes off onto other servers so that your web site remains nice and snappy.

You could try to add multi-threading and parallelism to your web application, by using TaskFactory and all that other stuff (for many folks, this is the route they take), but it doesn't make it very easy to separate your application if you need to, and break those big, resource-hogging pieces off if it becomes necessary.

I urge you to consider a queue-based solution.


Update:

For samples and information on how to implement this type of solution, see the following:

Also, consider glancing at this StackOverflow question for a quick crash course on the bare minimimum amount of code required.

A final note: MSMQ is built into certain flavors of Windows, and can be added to it through the Add/Remove Programs feature of the Control Panel. However, how you install it will depend on your specific flavor and version of Windows. A simple Google search will help you to find the appropriate instructions.

Good luck!

Community
  • 1
  • 1
Mike Hofer
  • 16,477
  • 11
  • 74
  • 110
  • 1
    You should never let a thread live longer than a page request unless you register that thread with [`QueueBackgroundWorkItem`](https://msdn.microsoft.com/en-us/library/dn636892(v=vs.110).aspx) on 4.5.2 (or some [3rd party library](https://github.com/StephenCleary/AspNetBackgroundTasks) if you cant upgrade to 4.5.2) otherwise it is very possible that your program will have its AppDomain shut down before your task finishes (And if you do register it you only get up to 90 additional seconds by default to finish your work). If you got rid the 3rd paragraph or showed the correct way I would +1 – Scott Chamberlain Jun 24 '15 at 16:56
  • 1
    @ScottChamberlain I, personally, don't advocate TaskFactory, async, await, or any of that in the web site. Long-running processes belong on a separate server, with some sort of message-passing system in place for notification. You've only highlighted one more reason why one should do so. – Mike Hofer Jun 24 '15 at 17:02
  • If i were to separate the long processing part of my application how would I go about this? Can you give me an example or resource showing me how this works? – J Hunt Jun 24 '15 at 20:10
  • @JHunt I've updated the post to provide the information you've requested. – Mike Hofer Jun 24 '15 at 20:40