Polling the database by multiple instances of the service is an option you need to take care of several issues:
- The select and update should be in one atomic transaction
- In case your service pulls some records to process and then crashes, how will you return them to the database
- You might get deadlocks, so your c# code should implement retries with random wait
You could use code like this to have atomic update/select by utilizing an UPDATE statement with OUTPUT clause:
DECLARE @fetched TABLE (id INT)
UPDATE D
SET D.Processed=1,D.ProcessId=123,D.StartTime=GETDATE()
OUTPUT inserted.id INTO @fetched
FROM queueData D
INNER JOIN (
SELECT TOP 10 T10.id
FROM queueData T10
WHERE T10.Processed=0
ORDER BY id
) Top10 ON D.id=Top10.id
SELECT * FROM @fetched
You can use MSMQ or Azure Service Bus directly, but also through the MassTransit API that will abstract details of the queue system for you.
There is another option, and that is to use the SQL Server Service Broker. The advantage of this approach is that you do not need to introduce an additional dependency on MSMQ or some other queue system, you just need to enable the Service Broker inside SQL server and then use TSQL to put messages in queues and to get messages from queues. Furthermore, SQL Server will take care of transactions.
-- enable the Service Broker
ALTER DATABASE test SET ENABLE_BROKER
GO
-- Message Type
CREATE MESSAGE TYPE TestMessage VALIDATION = NONE
GO
-- Contract
CREATE CONTRACT TestContract (TestMessage SENT BY INITIATOR)
GO
-- Send Queue
CREATE QUEUE TestSendQueue
GO
-- Receive Queue
CREATE QUEUE TestReceiveQueue
-- Create Send Service
CREATE SERVICE TestSendService ON QUEUE TestSendQueue (TestContract)
GO
-- Create Receive Service
CREATE SERVICE TestReceiveService ON QUEUE TestReceiveQueue (TestContract)
GO
-- Dialog using on contract
DECLARE @testDialog uniqueidentifier
DECLARE @Message VARCHAR(128)
BEGIN DIALOG CONVERSATION @testDialog
FROM SERVICE TestSendService
TO SERVICE 'TestReceiveService'
ON CONTRACT TestContract
WITH ENCRYPTION = OFF
-- Send messages
SET @Message = 'Very First Message';
SEND ON CONVERSATION @TestDialog MESSAGE TYPE TestMessage (@Message)
GO
-- Receive messages from Receive Queue
RECEIVE TOP(1) CONVERT(VARCHAR(MAX), message_body) AS Message
FROM TestReceiveQueue
GO
The above code is partly from http://blog.sqlauthority.com/2009/09/21/sql-server-intorduction-to-service-broker-and-sample-script/.