停止队列的N个消费者

时间:2013-01-04 17:52:51

标签: sql-server-2008 service-broker

我有一个SSBS队列,主进程发送M个消息到队列。有N个子进程逐个获取消息并处理它们。处理完所有消息后,子进程将退出。现在我正在做以下事情,

方法1:

主要进程在发送N消息后发送M“EndOfData”。但是它不能很好地工作,因为一些子进程可能会收到多个“EndOfData”消息,因此某些子进程永远不会收到消息。

方法2 :(扩展方法1)

为每个子流程分配一个ID,同时在“EndOfData”消息中嵌入一个ID。如果消息中的ID与其ID不匹配,则子进程回滚。但是,它会导致“poise message”问题,因为回滚太多而队列被禁用。

begin tran
begin try
    WAITFOR(
        RECEIVE TOP(1)
            @MessageType = message_type_name,
            @MessageBody = CAST(message_body AS xml)
        FROM
            TargetQueue
    ) , TIMEOUT 1000
    if @MessageType = 'EndOfData' and 
       @MessageBody.value('(//ID/text())[1]', 'int') <> @ID
    BEGIN 
        rollback tran
        waitfor delay '00:00:02'
    END 

有没有一种好方法可以实现它?

更新
子流程将执行以下步骤。

  1. 收到一条消息
  2. 如果“工作”,
    1. 处理消息(可能需要几分钟)
    2. 向队列发送“信息”消息,以便信息主要处理消息已被处理
  3. 如果是“EndOfData”,
    1. 向主流程
    2. 发送消息“退出”
    3. 收到“{存在”消息的https://..../EndDialog并退出
  4. 如果在2.2中发送了https://.../EndDialog条消息,则只需接收

2 个答案:

答案 0 :(得分:1)

另一种方法,假设N = 3

  1. 发送包含3的“EndOfData”类型的消息。
  2. 3个子进程中的一个收到此消息,发送包含2的响应消息,退出。所以剩下2个正在运行的子流程。
  3. 使用2接收回复,并发送包含2的“EndOfData”类型的消息。
  4. 2个子进程中的一个收到此消息,发送包含1的响应消息,退出。所以剩下1个正在运行的子流程。
  5. 使用1接收回复,并发送包含1的“EndOfData”类型的消息。
  6. 最后一个正在运行的子进程收到此消息,发送包含0的响应消息,退出。没有正在运行的子流程。
  7. 使用0接收回复,并停止发送“EndOfData”类型的消息。

答案 1 :(得分:0)

使用以下代码并将工作放在事务中。因此,脚本块可以在收到EndOfData消息后退出。

$conn = new-object Microsoft.SqlServer.Management.Common.ServerConnection
$conn.DatabaseName = "..."
$conn.BeginTransaction()
$conn.ExecuteNonQuery("Receive message;")
# do work
$conn.CommitTransaction()

http://msdn.microsoft.com/en-us/library/microsoft.sqlserver.management.common.serverconnection.committransaction.aspx