5

作为自动启动/停止我们的一些 NServiceBus 服务的努力的一部分,我想知道服务何时完成处理其输入队列中的所有消息。

问题是,当 NServiceBus 服务正在运行时,我的 C# 代码报告的消息比实际存在的消息少。所以当还剩下一条消息时,它认为队列是空的。如果服务停止,它会报告“正确”数量的消息。这很令人困惑,因为当我自己使用计算机管理应用程序中的专用队列视图检查队列时,它会显示“正确”的数字。

我正在使用以下 C# 代码的变体来查找消息计数:

var queue = new MessageQueue(path);
return queue.GetAllMessages().Length;

我知道当有很多消息时这会表现得很糟糕。我正在检查的队列一次只能有少量消息。

我查看了 其他 相关 问题,但没有找到我需要的帮助。

任何见解或建议将不胜感激!

更新:我应该提到此服务位于分发服务器之后,该分发服务器在尝试关闭此服务之前已关闭。所以我有信心不会将新消息添加到服务的输入队列中。

4

2 回答 2

2

问题是它实际上并不是“少一条消息”,而是取决于端点当前正在处理的消息数量,在多线程进程中,消息数量可能与线程数量一样高。

还有客户端进程继续向同一个队列发送消息的问题。

处理此问题的唯一“确定”方法可能是多次计数消息,中间有延迟,如果在一定次数的尝试中数量保持为零,您可以假设队列为空。

于 2012-10-04T07:29:35.083 回答
1

WMI 就是答案!这是代码的第一遍。它无疑可以改进。

public int GetMessageCount(string queuePath)
{
    const string query = "select * from Win32_PerfRawData_MSMQ_MSMQQueue";
    var query = new WqlObjectQuery(query);
    var searcher = new ManagementObjectSearcher(query);
    var queues = searcher.Get();

    foreach (ManagementObject queue in queues)
    {
        var name = queue["Name"].ToString();
        if (AreTheSameQueue(queuePath, name))
        {
            // Depending on the machine (32/64-bit), this value is a different type.
            // Casting directly to UInt64 or UInt32 only works on the relative CPU architecture.
            // To work around this run-time unknown, convert to string and then parse to int.
            var countAsString = queue["MessagesInQueue"].ToString();
            var messageCount = int.Parse(countAsString);
            return messageCount;
        }
    }

    return 0;
}

private static bool AreTheSameQueue(string path1, string path2)
{
    // Tests whether two queue paths are equivalent, accounting for differences
    // in case and length (if one path was truncated, for example by WMI).

    string sanitizedPath1 = Sanitize(path1);
    string sanitizedPath2 = Sanitize(path2);

    if (sanitizedPath1.Length > sanitizedPath2.Length)
    {
        return sanitizedPath1.StartsWith(sanitizedPath2);
    }

    if (sanitizedPath1.Length < sanitizedPath2.Length)
    {
        return sanitizedPath2.StartsWith(sanitizedPath1);
    }

    return sanitizedPath1 == sanitizedPath2;
}

private static string Sanitize(string queueName)
{
    var machineName = Environment.MachineName.ToLowerInvariant();
    return queueName.ToLowerInvariant().Replace(machineName, ".");
}
于 2012-10-04T18:55:24.177 回答