使用SSB在对话中发送和接收多条消息

时间:2013-08-29 22:08:45

标签: sql-server sql-server-2012 service-broker

有时候我需要将我的一些消息组合在一起,这样我们的工作流程就可以按顺序处理它们。

但我发现的每一个例子都只显示了如何在每个对话中做一条消息。

我正在寻找的是一个在对话中发送多条消息的示例,以及一个显示如何处理它们的示例。 (我可能会发送它们两个,但我似乎只能找到一个。)

1 个答案:

答案 0 :(得分:1)

对话提供了按顺序处理邮件的边界 - 因此您需要使用相同的ConversationId发送组中的所有邮件。我这样做的方法是使用一个实用程序表,在创建时存储ConversationId,以便每次发送消息时,它会查找相应的conversationid以将其发送。

SELECT @conversationHandle = ConversationHandle FROM Qproc.SessionConversation
WHERE 
FromService = @fromService
AND ToService = @toService
AND OnContract = @onContract
AND Terminated IS NULL

IF @conversationHandle IS NULL
BEGIN
    BEGIN DIALOG CONVERSATION @conversationHandle
        FROM SERVICE @fromService
        TO SERVICE @toService
        ON CONTRACT @onContract
        WITH ENCRYPTION = OFF; --, LIFETIME = 60*60*24*100;

    -- Store the ongoing conversation for further use
    INSERT INTO QProc.SessionConversation ( FromService, ToService, OnContract,ConversationHandle)
    VALUES(     @fromService,   @toService, @onContract,    @conversationHandle )
END


    -- Create the dialog timer, timeout is seconds; this will notify the ClientQueue if nothing has happened on the conversation
    --in the timeout period
    BEGIN CONVERSATION TIMER (@conversationHandle) TIMEOUT = 60*8;
    SEND ON CONVERSATION @conversationHandle
    MESSAGE TYPE [http://COMPANYNAME/AsyncTriggerRequestMesssage]
        (@messageBody);

你只在另一端看到一条消息的原因是与会话组锁定有关 - 你应该阅读这个以了解发生了什么,但基本上一旦消息处理程序看到了消息,它的观点就是消息队列仅限于一个对话。重复使用相同的conversationID后,这不会成为问题。这是一个示例接收:

DECLARE @RecvReqDlgHandle UNIQUEIDENTIFIER;
DECLARE @RecvReqMsg VARCHAR(8000);
DECLARE @RecvReqMsgName sysname;


WHILE (1=1)
    BEGIN
        BEGIN TRANSACTION;

        WAITFOR
        ( RECEIVE TOP(1)
            @RecvReqDlgHandle = conversation_handle,
            @RecvReqMsg = message_body,
            @RecvReqMsgName = message_type_name
          FROM  QProc.AsyncTaskServiceQueue
        ), TIMEOUT 500;

        IF @@ROWCOUNT=0
        BEGIN
            ROLLBACK TRANSACTION;
            BREAK
        END


        IF @RecvReqMsgName = 'http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog' 
            BEGIN
            END CONVERSATION @RecvReqDlgHandle;
            END

        IF @RecvReqMsgName='http://COMPANYNAME/AsyncTriggerRequestMesssage'
            BEGIN
                DECLARE @BodyDoc XML;
                SET @BodyDoc=CONVERT(XML, @RecvReqMsg)  ;   
                EXEC QProc.AsyncTaskRunTask @BodyDoc;

            END 

        COMMIT TRANSACTION;

    END

最后,你需要在不再使用这些对话后清理这些对话,如下所示:

DECLARE @conversationHandle UNIQUEIDENTIFIER;
DECLARE @messageTypeName SYSNAME;

BEGIN TRANSACTION;

RECEIVE TOP(1) 
    @conversationHandle = conversation_handle,
    @messageTypeName = message_type_name
FROM QProc.AsyncTaskClientQueue;

IF @conversationHandle IS NOT NULL
BEGIN
    --If the DialogTimer message arrives, then there has been no activity on this conversation for a while (see timeout setting in [QProc].[DispatchAsyncTaskMessage])
    --so we terminate gracefully and go home.


    IF @messageTypeName = 'http://schemas.microsoft.com/SQL/ServiceBroker/DialogTimer'
    OR @messageTypeName = 'http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog'
    BEGIN
        END CONVERSATION @conversationHandle;
        UPDATE Qproc.SessionConversation SET TERMINATED = getUtcDate() WHERE ConversationHandle = @conversationHandle;

    END
    END

COMMIT TRANSACTION;