Handling Poison Messages Sample Code in BOL wrong?

In the "Example: Detecting a Poison Message" section, it reads:

This Transact-SQL example shows a simple, stateless service that includes logic for handling poison messages. Before the stored procedure receives a message, the procedure saves the transaction. When the procedure cannot process a message, the procedurerolls the transaction back to the save point. The partial rollback returns the message to the queue while continuing to hold a lock on the conversation group for the message.

BEGIN TRANSACTION ;
DECLARE @conversationHandle UNIQUEIDENTIFIER ;
DECLARE @messageBody VARBINARY(MAX) ;
DECLARE @messageTypeName NVARCHAR(256) ;

SAVE TRANSACTION UndoReceive ;

WAITFOR (
RECEIVE TOP(1)
@messageTypeName = message_type_name,
@messageBody = message_body,
@conversationHandle = conversation_handle
FROM ExpenseQueue
), TIMEOUT 500 ;

<error occurs -- rollback needed>

IF @@ERROR <> 0
BEGIN
ROLLBACK TRANSACTION UndoReceive ;
EXEC TrackMessage @conversationHandle ;
END ;

<rest of example...>

After trying something similar, I believe that the "ROLLBACK TRANSACTION UndoReceive" statementreleases the lock on the conversation group. This means that the TrackMessage routine is not guaranteed exclusive access to the state data referenced by the @conversationHandle uniqueidentifier which could lead to data corruption.

To fix it, I think you need to have something like this:

begin tran;

-- obtain an explicit lock on the conversation group
declare @cgid uniqueidentifier;
waitfor (
get conversation group @cgid from ExpenseQueue;
), timeout 500;

-- handle possibly null @cgid here...

save tran UndoReceive;

receive top(1)
@messageTypeName = message_type_name,
@messageBody = message_body,
@conversationHandle = conversation_handle
from ExpenseQueue
where conversation_group_id = @cgid;

<error occurs -- rollback needed>

if @@error <> 0
begin
rollback transaction UndoReceive;
exec TrackMessage @conversation_handle;
end;

<rest of example...>

I would like some feedback on if my understanding is correct. I would like to avoid data corruption problems in our code.

Thanks -- Keith.

[2877 byte] By [Slamhart] at [2008-1-13]
# 1

The code is wrong because if you roll back the receive, the message is put back on the queue. the savepoint should be after the receive.

Roger_MS at 2007-9-9 > top of Msdn Tech,SQL Server,SQL Service Broker...

SQL Server

Site Classified