What is the optimum timer interval? .NET Windows Service
I have a .NET Windows Service that has a timer with interval set to 10 seconds. Every 10 se开发者_StackOverflowconds, it queries the database for any work to be done, picks up top 3 work items and processes them. The time taken to process each work item would depend on the user. It might range from a few seconds to several minutes.
I feel that 10 seconds is too short. I picked a low interval as the user is waiting for the process to be completed (they see a progress bar in the front end) and the faster the service picks up the work, the better. Also, the # of work items (three) was picked in random.
I do have "lock(this)" in my code to prevent one thread from stepping over the other. Is a short duration of 10 seconds okay in production environments?
EDIT: Also, does it make sense that I am picking only 3 items every time to be processed.
...Also, does it make sense that I am picking only 3 items every time to be processed...
Having a hard number of items to pick up could be dangerous. You have the potential to have items enter the queue faster than they can be processed. Consider what would happen if more than three items get enqueued every ten seconds. You would begin to see that it takes longer and longer for an item to get processed.
Either spawning additional threads or using an event-driven approach might be better.
I am currently handling something like this at work, with the main timer fetching from a stored procedure the work to be done each second (1000 ms).
Though, the fetching is not limited to X items (like 3 in your example).
I just add as many Threads as needed and let the framework handle them correctly.
I tried to decouple all the code in the way i don't need to use any lock
.
I save to db all the log informations and I have another timer (30 minutes interval) eventually fetching the errors and mail them to me.
You should have no problems with a 1 second timer, assuming you are giving all the work to another thread, different from the timer one.
Your service interval should be independent of the UI. One way to accomplish this is to have a flag for each work item in your database which marks them as "new", "in-process", or "done." Have your service pick up one item at a time and mark it as "in-process", do whatever it needs, and mark it as "done" when complete.
Your UI, then, would just poll that table and update the user with the status of each recently-modified row as necessary.
In this way, your timer interval becomes irrelevant for any consideration other than UI latency. You are also able to run multiple service threads without sacrificing efficiency (three threads could handle three items if you're processing them one at a time, instead of a single thread grabbing three), there's little or no opportunity for a race condition, etc.
Also, be sure to disable your timer while processing, or you run the risk of making your process method reentrant (interrupts itself).
I suppose that would depend on how complicated your query is. If it's a simple query that returns instantly and is only being run by a single service every 10 seconds, I doubt it'll be an issue, but I know nothing of your environment so don't hold me to that.
If you're looking for another solution altogether, you could look at a messaging architecture instead of polling.
Basically in this scenario, whatever system you have that's adding the work to the database in the first place can fire off a message to your service to let it know that there's work to do. Then your service doesn't need to poll anything, it just sits and waits for a notification that it needs to check the database. Alternatively, you could include the work to do in the message itself and let the service process it and store what needs to be stored in the database itself.
If you're interested in messaging, take a look into NServiceBus. It's basically a wrapper around MSMQ and will open your mind to a whole new world of ideas concerning inter-connected systems.
The options are endless really.
I would use the interval of 10 seconds.
Do another check when a user process has completed (to prevent an unnecessary 10sec wait)
You could look into the SQLDependency class to catch database events. That would be even better, but a bit more difficult to implement.
For more information on the SQLDependecy look here:
http://www.codeproject.com/KB/database/chatter.aspx
It's a hard questions to answer; your production environment could have a hardware configuration bigger than your comparative environment, so your queue can be processed faster than current values.
If you don't want to guess, try to implement a queue based winservice. That service will read a MSMQ queue and take a work item at time and process it. So you just need to ask that queue if you still got work items to process and you can do that in any frequency you want, let's say, 1 second.
Most important thing is to make sure you don't go get more work items while you still have work to do..
BTW, you should to read this: Why lock(this) is bad.
精彩评论