作为自动启动/停止某些NServiceBus服务的努力的一部分,我想知道服务何时完成处理其输入队列中的所有消息。
问题在于,当NServiceBus服务正在运行时,我的C#代码报告的消息少于实际消息。所以当剩下一条消息时,它认为队列是空的。如果服务停止,它将报告“正确”的消息数。这很令人困惑,因为当我使用“计算机管理”应用程序中的“专用队列”视图自行检查队列时,它会显示“正确”的数字。
我正在使用以下C#代码的变体来查找邮件计数:
var queue = new MessageQueue(path);
return queue.GetAllMessages().Length;
我知道当有很多消息时,这会表现得非常糟糕。我正在检查的队列一次只能有一些消息。
我看过了 other related questions, 但是没有找到我需要的帮助。
任何见解或建议都将不胜感激!
更新:我应该提到此服务位于分发服务器后面,该服务器在尝试关闭此服务之前已关闭。所以我有信心不会将新消息添加到服务的输入队列中。
答案 0 :(得分:2)
问题在于它实际上并不是“少一条消息”,而是依赖于端点当前正在处理的消息数量,在多线程进程中,它可以与线程数一样高。< / p>
还存在客户端进程继续向同一队列发送消息的问题。
处理此问题的唯一“确定”方法可能是通过多次计算消息并在两者之间延迟,如果数字在一定次数的尝试中保持为零,则可以假设队列为空。
答案 1 :(得分: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, ".");
}