views:

38

answers:

4

I’m looking for the best way of using threads considering scalability and performance.

In my site I have two scenarios that need threading:

  1. UI trigger: for example the user clicks a button, the server should read data from the DB and send some emails. Those actions take time and I don’t want the user request getting delayed. This scenario happens very frequently.

  2. Background service: when the app starts it trigger a thread that run every 10 min, read from the DB and send emails.

The solutions I found:

A. Use thread pool - BeginInvoke: This is what I use today for both scenarios. It works fine, but it uses the same threads that serve the pages, so I think I may run into scalability issues, can this become a problem?

B. No use of the pool – ThreadStart: I know starting a new thread takes more resources then using a thread pool. Can this approach work better for my scenarios? What is the best way to reuse the opened threads?

C. Custom thread pool: Because my scenarios occurs frequently maybe the best way is to start a new thread pool?

Thanks.

+4  A: 

I would personally put this into a different service. Make your UI action write to the database, and have a separate service which either polls the database or reacts to a trigger, and sends the emails at that point.

By separating it into a different service, you don't need to worry about AppDomain recycling etc - and you can put it on an entire different server if and when you want to. I think it'll give you a more flexible solution.

Jon Skeet
+1 nice decoupling and better fault tolerance.
Brian Rasmussen
Is it true for both scenarios? Or the first one can be solved by using Asynchronous Pages? Currently I’m on a shared host so different service isn’t an option, if I had to use threading which option is better? Will BeginInvoke become a scalability problem?
SirMoreno
I suspect either using a separate thread or the thread pool would work. Given that you don't want the user to have to wait, I'm not sure that asynchronous pages are going to help you much. I don't know much about them, but they seem to be about making long-running requests more efficient - you don't want your request to be long-running, you just want to make it start a background task.
Jon Skeet
So if I’m running on the same server am I better off with the webservice solution or the separate thread one?
SirMoreno
@SirMoreno: A web service would be a more logical split, but more work. Are you expecting to always be on this hosted service?
Jon Skeet
No, I'm looking for a solution that will work well on a shard host and still be relevant for future growth.
SirMoreno
A: 

I do this kind of thing by calling a webservice, which then calls a method using a delegate asynchronously. The original webservice call returns a Guid to allow tracking of the processing.

ck
A: 

For the first scenario use ASP.NET Asynchronous Pages. Async Pages are very good choice when it comes to scalability, because during async execution HTTP request thread is released and can be re-used.

I agree with Jon Skeet, that for second scenario you should use separate service - windows service is a good choice here.

Vitaliy Liptchinsky
A: 

Out of your three solutions, don't use BeginInvoke. As you said, it will have a negative impact on scalability.

Between the other two, if the tasks are truly background and the user isn't waiting for a response, then a single, permanent thread should do the job. A thread pool makes more sense when you have multiple tasks that should be executing in parallel.

However, keep in mind that web servers sometimes crash, AppPools recycle, etc. So if any of the queued work needs to be reliably executed, then moving it out of process is a probably a better idea (such as into a Windows Service). One way of doing that, which preserves the order of requests and maintains persistence, is to use Service Broker. You write the request to a Service Broker queue from your web tier (with an async request), and then read those messages from a service running on the same machine or a different one. You can also scale nicely that way by simply adding more instances of the service (or more threads in it).

In case it helps, I walk through using both a background thread and Service Broker in detail in my book, including code examples: Ultra-Fast ASP.NET.

RickNZ