在Sql Server中使用服务代理调用异步过程

时间:2017-09-13 07:13:18

标签: sql sql-server message-queue service-broker loose-coupling

我有一个按计划每天运行的备份程序(生产),并且定期使用生成的备份来刷新较低的环境。我正在构建一个自动解决方案,将.bak文件下载到较低的环境(不同的服务器)。我不愿意在备份中使用 MIRROR TO 选项,因为如果镜像失败,它可能会影响正常的备份操作。我这里想要使用服务代理,并在备份过程结束时异步触发从prod到较低环境的文件复制。我在理解服务代理,消息类型,服务,队列和合同方面付出了很多努力。一切都很好,直到这里。现在我只想了解如何使用服务代理在备份结束时使用一些自定义逻辑触发filecopy过程。我使用以下脚本来解释服务代理。有人指导我如何构建解决方案。

------------------------------------------------------------SETUP--------------------------------------------

CREATE MESSAGE TYPE [//SBTest/SBSample/RequestMessage] VALIDATION=WELL_FORMED_XML;

CREATE MESSAGE TYPE [//SBTest/SBSample/ReplyMessage] VALIDATION=WELL_FORMED_XML; 
-------------------------------------------------------------------------------------------------------------
CREATE CONTRACT [//SBTest/SBSample/SBContract]
(
[//SBTest/SBSample/RequestMessage] SENT BY INITIATOR ,
[//SBTest/SBSample/ReplyMessage] SENT BY TARGET 
);
-------------------------------------------------------------------------------------------------------------
CREATE QUEUE SBInitiatorQueue; 

CREATE QUEUE SBTargetQueue; 
-------------------------------------------------------------------------------------------------------------
CREATE SERVICE [//SBTest/SBSample/SBInitiatorService] ON QUEUE SBInitiatorQueue; 

CREATE SERVICE [//SBTest/SBSample/SBTargetService] ON QUEUE SBTargetQueue ([//SBTest/SBSample/SBContract]); 

-------------------------------------------------------------------------------------------------------------





-------------------------------------------------------INITIATE QUE-----------------------------------------
DECLARE @InitDlgHandle UNIQUEIDENTIFIER
DECLARE @RequestMessage VARCHAR(1000) 

BEGIN TRAN 

--Determine the Initiator Service, Target Service and the Contract 

BEGIN DIALOG @InitDlgHandle
FROM SERVICE [//SBTest/SBSample/SBInitiatorService] TO SERVICE'//SBTest/SBSample/SBTargetService'
ON CONTRACT
[//SBTest/SBSample/SBContract]
WITH ENCRYPTION=OFF; 


--Prepare the Message
SELECT @RequestMessage = N'HAHA'; 


--Send the Message
SEND ON CONVERSATION @InitDlgHandle 
MESSAGE TYPE
[//SBTest/SBSample/RequestMessage]
(@RequestMessage);

SELECT @RequestMessage AS SentRequestMessage;

COMMIT TRAN 
---------------------------------------------------------------------------------------------------------------






-------------------------------------------------------READ QUE-------------------------------------------------

\DECLARE @TargetDlgHandle UNIQUEIDENTIFIER
DECLARE @ReplyMessage VARCHAR(1000)
DECLARE @ReplyMessageName Sysname 

BEGIN TRAN; 

--Receive message from Initiator
RECEIVE TOP(1)
@TargetDlgHandle=Conversation_Handle, @ReplyMessage=Message_Body, @ReplyMessageName=Message_Type_Name
 FROM SBTargetQueue; 

SELECT @ReplyMessage AS ReceivedRequestMessage; 

-- Confirm and Send a reply
IF @ReplyMessageName=N'HAHA'

BEGIN
DECLARE @RplyMsg VARCHAR(1000)

SELECT @RplyMsg =N'HI'; 

SEND ON CONVERSATION @TargetDlgHandle
MESSAGE TYPE
[//SBTest/SBSample/ReplyMessage]
(@RplyMsg);
END CONVERSATION @TargetDlgHandle;

END 

SELECT @RplyMsg AS SentReplyMessage; 

COMMIT TRAN;

-------------------------------------------------------------------------------------------------------------------

1 个答案:

答案 0 :(得分:2)

使用“内部激活”进行触发。您需要创建一个存储过程,当消息进入队列,从队列中读取然后完成工作时将触发该存储过程。 改编自link

CREATE PROCEDURE TargetActivProc
AS
  DECLARE @RecvReqDlgHandle UNIQUEIDENTIFIER;
  DECLARE @RecvReqMsg NVARCHAR(100);
  DECLARE @RecvReqMsgName sysname;

  WHILE (1=1)
  BEGIN

    BEGIN TRANSACTION;

    WAITFOR
    ( RECEIVE TOP(1)
        @RecvReqDlgHandle = conversation_handle,
        @RecvReqMsg = message_body,
        @RecvReqMsgName = message_type_name
      FROM TargetQueueIntAct
    ), TIMEOUT 5000;

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

    IF @RecvReqMsgName =
       N'//SBTest/SBSample/RequestMessage'
    BEGIN

      --do work here
    END
    ELSE IF @RecvReqMsgName =
        N'http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog'
    BEGIN
       END CONVERSATION @RecvReqDlgHandle;
    END
    ELSE IF @RecvReqMsgName =
        N'http://schemas.microsoft.com/SQL/ServiceBroker/Error'
    BEGIN
       END CONVERSATION @RecvReqDlgHandle;
    END

    COMMIT TRANSACTION;

  END
GO

下一部分是在队列上启用激活

ALTER QUEUE SBTargetQueue
    WITH ACTIVATION
    ( STATUS = ON,
      PROCEDURE_NAME = TargetActivProc,
      MAX_QUEUE_READERS = 1,
      EXECUTE AS SELF
    );

当邮件到达队列时,该过程将被激活,并将保持激活状态并循环,直到队列为空。