Question

I setup Internal Activation for two stored procedures. One, inserts one or more records , the other, updates one or more records in the same table. So, I have two initiator, two target queues. It works fine on development so far, but I wonder what types of problems I might encounter when we move it to prod where these two stored procedures are frequently called. We have already experiencing deadlock issues caused by these two stored procedures. Asynchronous execution is my main goal with this implementation.

Questions :

  1. Is there a way to use one target queue for both stored procedures to prevent any chance of deadlocks?

  2. Is there anything I can do to make it more reliable? like one execution error should not stop incoming requests to the queue?

  3. Tips to improve scalability (high number of execution per second)?

  4. Can I set RETRY if there is a deadlock?

Here is the partial code of the insert stored procedure;

CREATE QUEUE   [RecordAddUsersQueue];
CREATE SERVICE [RecordAddUsersService] ON QUEUE [RecordAddUsersQueue];

ALTER QUEUE [AddUsersQueue] WITH ACTIVATION 
(     STATUS            = ON,
      MAX_QUEUE_READERS = 1, --or 10?
      PROCEDURE_NAME    = usp_AddInstanceUsers,
      EXECUTE AS OWNER);

CREATE PROCEDURE [dbo].[usp_AddInstanceUsers] @UsersXml xml
AS
BEGIN
  DECLARE @Handle uniqueidentifier;

  BEGIN DIALOG CONVERSATION @Handle
  FROM SERVICE [RecordAddUsersService]
  TO   SERVICE 'AddUsersService'
  ON  CONTRACT [AddUsersContract]
  WITH ENCRYPTION = OFF;

  SEND ON CONVERSATION @Handle
  MESSAGE TYPE [AddUsersXML] (@UsersXml);
END
GO

CREATE PROCEDURE [dbo].[usp_SB_AddInstanceUsers]
AS
BEGIN
  DECLARE @Handle uniqueidentifier;
  DECLARE @MessageType sysname;
  DECLARE @UsersXML xml;

  WHILE (1 = 1)
  BEGIN
    BEGIN TRANSACTION;
      WAITFOR
      (RECEIVE TOP (1)
      @Handle      = conversation_handle,
      @MessageType = message_type_name,
      @UsersXML    = message_body
      FROM [AddUsersQueue]), TIMEOUT 5000;
      IF (@@ROWCOUNT = 0)
      BEGIN
        ROLLBACK TRANSACTION;
        BREAK;
      END

      IF (@MessageType = 'ReqAddUsersXML')
      BEGIN
        --<INSERT>....
        DECLARE @ReplyMsg nvarchar(100);
        SELECT
          @ReplyMsg = N'<ReplyMsg>Message for AddUsers Initiator service.</ReplyMsg>';
        SEND ON CONVERSATION @Handle
        MESSAGE TYPE [RepAddUsersXML] (@ReplyMsg);
      END

      ELSE
      IF @MessageType = N'http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog'
      BEGIN
        END CONVERSATION @Handle;
      END
      ELSE
      IF @MessageType = N'http://schemas.microsoft.com/SQL/ServiceBroker/Error'
      BEGIN
        END CONVERSATION @Handle;
      END
    COMMIT TRANSACTION;
  END
END
GO

Thank you,

Kuzey

Was it helpful?

Solution

Is there a way to use one target queue for both stored procedures to prevent any chance of deadlocks?

You can and you should. There is no reason for having two target services/queues/procedures. Send, to the same service, two different message types for the two operations you desire. The activated procedure should then execute logic for Add or logic for Update, depending on message type.

Is there anything I can do to make it more reliable? like one execution error should not stop incoming requests to the queue?

SSB activation will be very reliable, that's not going to be a problem. As long as you adhere strictly to transaction boundaries (do not commit dequeue operations before processing is complete), you'll never lose a message/update.

Tips to improve scalability (high number of execution per second)?

Read Writing Service Broker Procedures and Reusing Conversations. To achieve a high throughput processing, you will have to dequeue and process in batches (TOP(1000)) into @table variables. See Exception handling and nested transactions for a pattern that can be applied to process a batch of messages. You'll need to read and understand Conversation Group Locks.

Can I set RETRY if there is a deadlock?

No need to, SSB activation will retry for you. As you rollback, the dequeue (RECEIVE) will rollback thus making the messages again available for activation, and the procedure will automatically retry. Note that 5 rollbacks in a row will trigger the poison message trap

MAX_QUEUE_READERS = 1, --or 10?

If 1 cannot handle the load, add more. As long as you understand proper conversation group locking, the parallel activated procedures should handle unrelated business items and never deadlock. If you encounter deadlocks between instances of activated procedure on the same queue, it means you have a flaw in the conversation group logic and you allow messages seen by SSB as uncorrelated (different groups) to modify the same database records (same business entities) and lead to deadlocks.

BTW, you must have an activated procedure on the initiator service queue as well. See How to prevent conversation endpoint leaks.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top