【问题标题】:SQL Server Service Broker - Message TimeoutSQL Server 服务代理 - 消息超时
【发布时间】:2011-11-05 16:57:30
【问题描述】:

我正在研究 sql server service broker 作为我们应用程序的消息处理技术。

在我们的场景中,从一个客户端应用程序 (WPF) 发送的消息需要在服务代理中排队等待其他客户端应用程序 (android) 接收。消息是时间敏感的,需要在被发布到队列后的“X”分钟(例如 2 分钟)内被接收者接收,如果此时无法接收,则消息需要过期并从队列中删除排队。

有没有办法告诉服务代理在“x”分钟后超时消息?

编辑:添加了我用来测试的脚本。

CREATE DATABASE ServiceBrokerTest
GO

ALTER DATABASE ServiceBrokerTest SET ENABLE_BROKER WITH ROLLBACK IMMEDIATE 
GO

/****** Object:  MessageType [SampleMsgType] ***/
CREATE MESSAGE TYPE [SampleMsgType] AUTHORIZATION [dbo] VALIDATION = NONE
GO

/****** Object:  ServiceContract [MsgContract]    ******/
CREATE CONTRACT [MsgContract] AUTHORIZATION [dbo] ([SampleMsgType] SENT BY INITIATOR)
GO

/****** Object:  ServiceQueue [dbo].[Queue1]    ******/
CREATE QUEUE [dbo].[Queue1] WITH STATUS = ON , RETENTION = OFF , POISON_MESSAGE_HANDLING (STATUS = ON)  ON [PRIMARY] 
GO

/****** Object:  BrokerService [MsgService]    ******/
CREATE SERVICE [MsgService]  AUTHORIZATION [dbo]  ON QUEUE [dbo].[Queue1] ([MsgContract])
GO

/****** Object:  StoredProcedure [dbo].[SendMsg]  ******/
CREATE PROC [dbo].[SendMsg]
@msg NVARCHAR(MAX)
AS

BEGIN
    SET NOCOUNT ON
    DECLARE @handle UNIQUEIDENTIFIER

    BEGIN TRANSACTION
        BEGIN dialog @handle 
            FROM SERVICE [MsgService]
            TO SERVICE 'MsgService'
            ON CONTRACT [MsgContract]
            WITH ENCRYPTION = OFF, LIFETIME = 20

        ;SEND ON CONVERSATION @handle
            MESSAGE TYPE [SampleMsgType] (@msg)
        END CONVERSATION @handle
    COMMIT TRANSACTION
END

/****** Object:  StoredProcedure [dbo].[ReceiveMsg] ******/
CREATE PROC [dbo].[ReceiveMsg]
@msg NVARCHAR(MAX) OUT

AS

BEGIN
    SET NOCOUNT ON
    DECLARE @handle UNIQUEIDENTIFIER

    DECLARE @msgTable TABLE (
        handle UNIQUEIDENTIFIER,
        msg NVARCHAR(MAX),
        msgType VARCHAR(300));

    SET @handle = NULL

    WAITFOR (
        RECEIVE [conversation_handle], message_body, message_type_name
        FROM [dbo].[Queue1]
        INTO @msgTable
        ), TIMEOUT 25000

        SELECT @handle = handle
        FROM @msgTable
        WHERE msgType = 'http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog'

        IF @handle is not null
            BEGIN 
                END CONVERSATION @handle
            END

        SELECT @msg = msg
        FROM @msgTable
        WHERE msgType = 'SampleMsgType'
END 

GO

【问题讨论】:

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


    【解决方案1】:

    可以在BEGIN DIALOG 语句期间指定对话生命周期:

    BEGIN DIALOG @handle
    FROM SERVICE [...]
    TO SERVICE '...'
    ON CONTRACT [...]
    , LIFETIME = <dialog lifetime>;
    

    对话框必须在其生命周期内完成(双方都结束),否则会出错。因此,您可以启动一个生命周期为 2 分钟的对话,并在其上发送一条或多条消息。目标必须在这 2 分钟内接收并处理消息,否则对话框将出错。

    您也可以使用conversation priorities 并在更高优先级的通道上发送时间敏感消息。这将确保 Service Broker 传输优先考虑您的敏感消息,并且客户端应用程序 RECEIVE 语句“冒泡”优先级较高的时间敏感消息,并且它们首先被接收。

    【讨论】:

    • 感谢您的回复。我按照您的建议进行了尝试,但消息在设置的生命周期(25 秒)后没有过期。即使在 25 秒后,我也能收到消息。我已经编辑了我的问题以包含我正在使用的脚本。如果你能指出我在那里做错了什么,那就太好了。
    • @muruge - 我相信您需要在对话的发起者一侧保持对话框打开,以便获取代理超时错误消息。
    • @muruge - 你还在使用 SSB 的“即发即弃”反模式,Remus 可以告诉你一切。
    • @etliens - 谢谢。这有帮助。
    【解决方案2】:

    在不使用对话框生命周期的情况下实现您想要的替代方法。

    在您的消息负载中发送“SentDate”,并在您的激活过程中处理“过期”消息。这使您能够明确决定消息过期时要执行的操作。 (即忽略过期消息,记录到错误表,通知发件人哪些消息被延迟接收等。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-09-20
      • 1970-01-01
      • 1970-01-01
      • 2010-12-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-26
      相关资源
      最近更新 更多