normalian blog

Let's talk about Microsoft Azure, ASP.NET and Java!

CloudQueueMessage.DequeueCountの用途と使い方について

以前に記述した id:waritohutsu:20091218:1261092402 の記事では、「Windows Azure基盤側にはCloudQueueMessageのデキューされた回数は実装されているが、Windows Azure SDK にはデキューされた回数を取得できるAPIが公開されていない」と記述しましたが、Windows Azure SDK 1.1では、ついにデキューされた回数は取得できるようになりました!!
今回の記事では、CloudQueueMessage.DequeueCountの用途と使い方を紹介します。

CloudQueueMessage.DequeueCountの用途

Windows Azureのキューストレージに限らず、キューを利用した場合に検討されるのが「キューのメッセージを処理している最中に例外が発生した場合に無限ループになる」という問題です(下図参照)。

凄い手抜きなので私がへこんで来た事はさておき、以下のような問題が起きます。

  1. クライアント側からキューにメッセージを送り、キューにメッセージが格納される
  2. サーバ側がキューからメッセージを取得する
  3. サーバ側で取得したメッセージを処理中に例外(障害)が発生する。
  4. 例外を発生させたメッセージがキューに戻るが、再度同メッセージをサーバ側で取得して再び例外が発生する(以下、無限ループ)

上記の問題を解決するため、一定回数以上デキュー処理を行ったメッセージに特別な処理を行う必要があります。この「一定回数以上デキュー処理を行ったメッセージ」として判別するため、CloudQueueMessage.DequeueCountが利用できます。

CloudQueueMessage.DequeueCountの使い方(MSDNドキュメント)

Windows Azure SDK 1.0 2009 Novemberが公開された当時には駄目駄目でしたが、先ほど確認したところMSDNにCloudQueueMessage.DequeueCountが追記されています。具体的な使用例は以下となります。

//キューからメッセージを取得
CloudQueueMessage msg = queue.GetMessage();

//メッセージに格納された文字列とデキューカウントを表示
Trace.TraceInformation(
    "キューからDequeue={0}、デキュー回数={1}回目",
    msg.AsString,
    msg.DequeueCount);
queue.DeleteMessage(msg);

CloudQueueMessage.DequeueCountの使い方(動作確認に使用するサンプルアプリケーション)

@ITで公開されている記事 「Windows Azureストレージ開発入門(後編)初めてのブロブ&キュー・ストレージ開発」で使用されているキューストレージのサンプルアプリケーションを参考にします。機能概要としては以下になりますが、Wokerロール側の処理を変更しています。

  • Webロール側
    • ユーザが「発言内容」をテキストボックスに入力する。
    • ユーザが「キューへメッセージを発行」ボタンを押した際に、キューストレージ(myqueueキュー)へ「発言内容」を格納する。
  • Workerロール側(サンプルコードと日本語が微妙に合ってないなぁという自覚はあるが、面倒で修正はあきらめた)
    • 10秒に一度キューストレージ(myqueueキュー)を確認し、メッセージの内容とデキューカウントをTrace.WriteLineを出力する。
    • キューストレージから取得したメッセージが5回以上デキューされている場合は、エラーメッセージを出力してキューからメッセージを削除する。
    • キューストレージから取得したメッセージが「変態」を含む文字列の場合、例外メッセージを出力するが、キューからメッセージを削除しない。

また、Workerロールのキューメッセージ処理部分のサンプルコードを提示します。

//Webロール側からのメッセージを取得して表示する
while (true)
{
    try
    {
        //キューからのメッセージを取得
        CloudQueueMessage msg = queue.GetMessage();
        if (msg != null)
        {
            if (msg.DequeueCount >= 5 )
            {
                //5回以上デキュー済みなので、エラーメッセージを出力後にメッセージ削除
                Trace.Fail(string.Format("メッセージ{0}は5回以上デキューされましたが、処理が完了できませんでした",
                              msg.AsString));
                queue.DeleteMessage(msg);
            }
            else if (msg.AsString.Contains("変態"))
            {
                //例外が発生するので、メッセージをキューから削除しない
                throw new ArgumentException("変態を含むメッセージは処理できない");
            }
            else
            {
                //メッセージを処理し、キューから削除する
                Trace.TraceInformation(
                    "キューからDequeue={0}、デキュー回数={1}回目",
                    msg.AsString,
                    msg.DequeueCount);
                queue.DeleteMessage(msg);
            }
        }
        else
        {
            Trace.TraceInformation("キュー内のメッセージが空です = null");
        }
        Thread.Sleep(10000);
    }
    catch (Exception ex)
    {
        Thread.Sleep(10000);
        Trace.TraceError(string.Format("キューの処理中に例外 '{0}'", ex.Message));
    }
}

CloudQueueMessage.DequeueCountの使い方(サンプルアプリケーションの動作)

サンプルアプリケーションを起動して、以下の処理を行いました。

  1. スタートメニューから Development Fabric UIを起動して、Workerロール側のインスタンスを選択する。
  2. Webロール側のテキストボックスに対して、「Shibayanは変態!って入力すると例外がでる」という文字列を入力し、「キューへメッセージを発行」ボタンを押す。
  3. Development Fabric UIのWorkerRole1のインスタンスが「5回以上デキューしたけど」処理できなかった旨のメッセージを出力していることを確認する。
  4. Webロール側のテキストボックスに対して、「割と普通は普通!って入力するとOK」という文字列を入力し、「キューへメッセージを発行」ボタンを押す。
  5. Development Fabric UIのWorkerRole1のインスタンスが、入力したメッセージとデキューカウントを出力していることを確認する。

オペレーションを行ったDevelopment Fabric UIのキャプチャは以下となります。