views:

128

answers:

5

Edit (again): Let me simplify my problem. I have a Windows Service that exposes some WCF endpoints with methods like:

int ExecuteQuery(string query) {
   // asynchronously execute query that may take 1 second to 20 minutes
   return queryId;
}

string GetStatus(int queryId) {
   // return the status of the query (# of results so far, etc)
}

What is the best way to implement the ExecuteQuery method? Should I just call ThreadPool.QueueUserWorkItem to get my query going?

Note that the actual work behind executing a query is done by load-balanced black box. I want to be able to have several queries going at the same time.

The analogy is a web browser that is downloading multiple files simultaneously and you have a download manager that can track the status of each file.

+3  A: 

Take a look at Microsoft Message Queuing (MSMQ):

Microsoft Message Queuing (MSMQ) technology enables applications running at different times to communicate across heterogeneous networks and systems that may be temporarily offline. MSMQ provides guaranteed message delivery, efficient routing, security, and priority-based messaging. It can be used to implement solutions for both asynchronous and synchronous messaging scenarios.

It's good to know that Windows Communication Foundation (WCF) can leverage queuing services offered by MSMQ.

Mehrdad Afshari
I was under the impression that MSMQ required a fair amount of infrastructure. Additionally, "who" would actually execute the queries in this case? Is MSMQ just the intermediary?
@intoorbit: MSMQ requires installation of the Windows component but it's fairly easy to get it to work. Besides, when you get it going, you get a bunch of awesome features for free. Yes, MSMQ just delivers the messages and you'll still have to process them manually. It can't do the actual processing itself but it removes the burden of establishing a communication infrastructure between the app and the service.
Mehrdad Afshari
I edited my question to diminish the importance of the communication channel. However, I do plan to check out MSMQ to see if it could be part of my solution. Even for transient, time-dependent, and non-critical requests, do you think it would be worthwhile?
@intoorbit: If you don't get any benefits from MSMQ then no. I wouldn't encourage you to use something just to be cool. You can use a simple WCF channel. Re the way you process things, in most cases, simply calling `ThreadPool.QueueUserWorkItem` to queue a work item works pretty well. It definitely *can* be used in Windows Services too. I'm not sure about what exactly you mean from X number of workers? You mean a single request is processed on X distinct servers or requests are load-balanced between X servers or something else?
Mehrdad Afshari
@Mehrdad I think I must have posed an overcomplicated question. I rephrased it again with some code to take one last stab at this. I meant that if I "execute a query", it is handled by some load-balanced black box and the results start streaming back to me. I want to return a "status id" to the user immediately and then have several queries going at once. Really, this is a lot like Firefox downloading X files at the same time and your download manager tells you how far along each one is.
A: 

Adding to the MSMQ answer, you could think about looking at using an Enterprise Service Bus (ESB) to handle these sorts of things, if future scalability is a concern. Check out NServiceBus for one .NET example.

Pete
+1  A: 

I use a Windows service for a very similar task and it works very well. I use database tables to queue requests and responses, as it gives me a persistent queue that can be accessed over the network from remote ASP.Net applications, and concurrency control through transactions.

A supervisor thread on a timer spawns workers whenever incoming requests need servicing. I use a separate database tables for configuration and control so that I can administer the service and pause the supervisor from an application without while leaving the service core running. Logging to a separate table is a convenient way to see what's happening from web apps and a local admin app.

I wouldn't use the ThreadPool for long-running threads, but instead create a worker class that runs in its own thread and uses callback methods to update the supervisor with progress and completion status.

ebpower
Yep... that is pretty much what I intend to do, and in my case I don't even need to persist state to a database. I asked this question because I figure that all the producer/consumer type code is done so often, there must be some code or patterns that already exist that I can tap into.
A: 

I would use WWF (4.0):

You can start long running transactions that can be handle in a few machines, execute task in parallel, failure support, friendly coding, you can manage it with appfabric, it is free...

Pablo Castilla
A: 

Either this is a trick question or a no-brainer... ThreadPool.QueueUserWorkItem is about the easiest way to go when you want to execute a piece of code concurrently. I'm sure you already knew that, so technically you have already answered your own question.

So if this is not a trick question, then are you asking exactly how to pass the query in the ThreadPool.QueueUserWorkItem?

Lirik
I guess I was probably thinking out loud here and made my problem seem more complicated than it was. There's a lot of "advice" out there that says "don't overuse the ThreadPool, especially for long-running tasks." I just wanted to see if there was any advice out there specific to my problem.
There is sentiment against using "long-running" tasks in a ThreadPool because if a task is waiting on another tasks to do some work and that task is waiting to be executed in the same ThreadPool, but the ThreadPool is full, then the queued task might never get executed and you'll get a deadlock. This can happen even with short-running tasks. I think if somebody is having this problem, then they've simply designed their program incorrectly...
Lirik