5

一部の NServiceBus サービスの開始/停止を自動化する取り組みの一環として、サービスが入力キュー内のすべてのメッセージの処理をいつ終了したかを知りたいです。

問題は、NServiceBus サービスの実行中に、私の C# コードが報告するメッセージが実際よりも 1 つ少ないことです。したがって、メッセージが 1 つ残っている場合、キューは空であると見なされます。サービスが停止している場合、「正しい」数のメッセージが報告されます。コンピュータ管理アプリケーションのプライベート キュー ビューを使用して自分でキューを調べると、「正しい」番号が表示されるため、これは紛らわしいです。

メッセージ数を見つけるために、次の C# コードのバリアントを使用しています。

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

多くのメッセージがある場合、これはひどく実行されることを私は知っています。私が検査しているキューには、一度に少数のメッセージしかありません。

関連する他の 質問を見 ましたが、必要なヘルプが見つかりませんでした。

洞察や提案をいただければ幸いです。

更新:このサービスは、このサービスをシャットダウンしようとする前にシャットダウンされるディストリビューターの背後にあることに言及する必要がありました。したがって、新しいメッセージがサービスの入力キューに追加されないことは確実です。

4

2 に答える 2

2

問題は、実際には「メッセージが 1 つ少ない」ということではなく、エンドポイントによって現在処理されているメッセージの数に依存していることです。これは、マルチスレッド プロセスでは、スレッドの数と同じになる可能性があります。

同じキューにメッセージを送信し続けるクライアント プロセスの問題もあります。

おそらく、これを処理する唯一の「確実な」方法は、間に遅延を設けてメッセージを複数回カウントし、特定の試行回数にわたって数がゼロのままである場合、キューが空であると想定できることです。

于 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 に答える