I have an ASP.NET application running on multiple IIS6 web servers, with a SQL Server 2005 database back-end.
I need to:
monitor the database for the completion of an external job event, and then
have exactly one web application instance submit some information to a web service
For (1) it seems like a SqlDependency would be the best approach (or just plain old polling). Each web application instance would register such a dependency when it starts up. 开发者_JAVA百科(I don't want to configure a 'master' instance because the failure of that instance would mean the task doesn't proceed, even if other instances are available. Thus my design is to ensure that if there is an instance available to do the work, then the work ought to proceed.)
For (2) I have been thinking of having some sort of flag in the database that the web application instances try to update once they receive the SqlDependency notification in (1), along the following line (greatly simplified):
UPDATE StatusTable SET TaskStatus = 1 WHERE TaskStatus = 0
SELECT @@ROWCOUNT
The idea is that only one application instance would have been able to update the TaskStatus, and thus only one instance would have a @@ROWCOUNT > 0. This would then be the instance 'elected' to submit the information to the web service.
What are the deficiencies with this approach? What are my other options? (Note: a separate service doing this work is not an option.)
A global 'flag' will not work, keep in mind that you have multiple waiters and multiple notifications, you don't want one 'waiter' to pick up all notifications. To reliable pick 'exactly one' task, use UPDATE with OUTPUT:
UPDATE TOP(1) StatusTable
SET Status = 1
OUTPUT DELETED.TaskId
WHERE Status = 0;
This is the recommended, reliable, way to dequeue rows from tables used as queues, see the Queues paragraph in OUTPUT Clause.
But by now you should realize that 1) you are using tables as queues 2) you are receiving notifications from these queues and 3) you use Service Broker to deliver these notifications (via SqlDependency, which internally uses Service Broker). So why not use just plain Service Broker? You need a queue and a service and have each instance starts a WAITFOR(RECEIVE...) on this queue (which is not polling). The job of interest ends its work with a SEND to your service, notifying that a job is complete. Exactly one of your instances will pick up this notification and carry on the post-processing (ie. deliver the web service call). This way you cut out all the 'fluf' around the notifications (SqlDependency, global flag, tables used as queues) and you go against the bare-bone infrastructure which would be used by SqlDependency anyway.
精彩评论