views:

103

answers:

6

I want a certain action request to trigger a set of e-mail notifications. The user does something, and it sends the emails. However I do not want the user to wait for page response until the system generates and sends the e-mails. Should I use multithreading for this? Will this even work in ASP.NET MVC? I want the user to get a page response back and the system just finish sending the e-mails at it's own pace. Not even sure if this is possible or what the code would look like. (PS: Please don't offer me an alternative solution for sending e-mails, don't have time for that kind of reconfiguration.)

A: 

You probably can use ThreadPool.QueueUserWorkItem

CodeInChaos
A: 

Yes this is an appropriate time to use multi-threading.

One thing to look out for though is how will you express to the user when the email sending ultamitely fails? Not blocking the user is a good step to improving your UI. But it still needs to not provide a false sense of success when ultamitely it failed at a later time.

JaredPar
Good point, though in this situation the user should not be notified however I do want to know if it is failing. I'll think of something for that.
shogun
+1  A: 

I know you are not looking for alternatives, but using a MessageQueue (such as MSMQ) could be a good solution for this problem in the future. Using multithreading in asp.net is normally discouraged, but in your current situation I don't see why you shouldn't. It is definitely possible, but beware of the pitfalls related to multithreading (stolen here):

•There is a runtime overhead associated with creating and destroying threads. When your application creates and destroys threads frequently, this overhead affects the overall application performance. •Having too many threads running at the same time decreases the performance of your entire system. This is because your system is attempting to give each thread a time slot to operate inside. •You should design your application well when you are going to use multithreading, or otherwise your application will be difficult to maintain and extend. •You should be careful when you implement a multithreading application, because threading bugs are difficult to debug and resolve.

klausbyskov
+2  A: 

SmtpClient.SendAsync is probably a better bet than manual threading, though multi-threading will work fine with the usual caveats.

http://msdn.microsoft.com/en-us/library/x5x13z6h.aspx

As other people have pointed out, success/failure cannot be indicated deterministically when the page returns before the send is actually complete.

A couple of observations when using asynchronous operations:

1) They will come back to bite you in some way or another. It's a risk versus benefit discussion. I like the SendAsync() method I proposed because it means forms can return instantly even if the email server takes a few seconds to respond. However, because it doesn't throw an exception, you can have a broken form and not even know it.

Of course unit testing should address this initially, but what if the production configuration file gets changed to point to a broken mail server? You won't know it, you won't see it in your logs, you only discover it when someone asks you why you never responded to the form they filled out. I speak from experience on this one. There are ways around this, but in practicality, async is always more work to test, debug, and maintain.

2) Threading in ASP.Net works in some situations if you understand the ThreadPool, app domain refreshes, locking, etc. I find that it is most useful for executing several operations at once to increase performance where the end result is deterministic, i.e. the application waits for all threads to complete. This way, you gain the performance benefits while still having a clear indication of results.

3) Threading/Async operations do not increase performance, only perceived performance. There may be some edge cases where that is not true (such as processor optimizations), but it's a good rule of thumb. Improperly used, threading can hurt performance or introduce instability.

The better scenario is out of process execution. For enterprise applications, I often move things out of the ASP.Net thread pool and into an execution service.

See this SO thread: http://stackoverflow.com/questions/3869784/designing-an-asynchronous-task-library-for-asp-net/3870308#3870308

Tim
+1  A: 

At the risk of violating your no-alternative-solution prime directive, I suggest that you write the email requests to a SQL Server table and use SQL Server's Database Mail feature. You could also write a Windows service that monitors the table and sends emails, logging successes and failures in another table that you view through a separate ASP.Net page.

ebpower
I like this approach. I've just recently implemented one where the messages are queued in a DB, and our scheduler software kicks off a process every 15 minutes that checks the queue and sends off a batch of e-mails. How much time do you have? I implemented that whole system somewhere in the 6 hour range (we had a scheduler system already in place -- do you have one available to you?).
Cory Larson
A: 

Don't know if any of the above links mentioned it, but don't forget to keep an eye on request timeout values, the queued items will still need to complete within that time period.

David