I am using a SQL Server database table as a work queue.
I have one writer and multiple readers.
The writer produces new records for the queue table (INSERT).
Each reader looks for records in a certain status (SELECT) to consume, takes one batch of records, marks each record as owned (UPDATE), processes them, and then marks all processed records as complete or failed (UPDATE). The workflow for the records is simple: The status goes from 'A' for Added, to 'B' for Being Processed, to either 'C' for Complete or 'F' for Failed. And the owner for each record goes from unset while in status 'A' to a unique-identifier identifying the reader for the remaining steps. The unique identifier (a Decimal) plus the status (nchar(1)) plus an additional batch id (int) that identifies the writer's larger batch are the three key fields in the processing. Also, the table has a timestamp field that LINQ uses for its concurrency checks.
I need to prevent locking delays and update failures due to two readers choosing the same records to process. As part of the processing work, a web service call is made that can take an indeterminate amount of time to complete. We pay the web service vendor by the transaction, so I do not want to make the call, then find out another process handled the same record. Such errors will cost us thousands of dollars.
I read this article:
Processing Data Queues in SQL Server with READPAST and UPDLOCK
That looked promising, but I decided to use LINQ to SQL. I read this article:
The latter says that there is no way to tell LINQ to use UPDLOCK short of crudely wrapping a SQL procedure. This is because LINQ uses optimistic concurrency and those features assume pessimistic locking.
So how do I solve this problem using features that LINQ does support? My application is multi-threaded, but I could have multiple instances running against the same queue table, so I cannot just have a single dispatcher hand off the records to each consumer thread.
I am using .NET 4.0. My application is a plain old Windows console application. The solution should work with SQL Server 2005 and SQL Server 2008 R2. I do not want to have to use a messaging system.
UPDATE: Further research on SO. Found this article:
The answer recommends having a dispatcher thread, which I ruled out.
UPDATE 2: Found another article on SO:
Atomically Mark and return a group of rows in database
This looks really promising. I would need to execute direct SQL, but once I have my records marked and get my IDs, the rest can happen in L2S.